This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
openclaw/skills/gsd-openclaw/.planning/phases/04-gsd-integration/04-01-PLAN.md
T

9.1 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
04-gsd-integration 01 execute 1
src/gsd_openclaw/user_context.py
src/gsd_openclaw/__init__.py
tests/test_user_context.py
tests/conftest.py
true
BRDG-06
truths artifacts key_links
User's project context persists across chat sessions
User context is stored in isolated per-user files
User context writes are atomic and crash-safe
Each user has independent project tracking
path provides min_lines
src/gsd_openclaw/user_context.py UserContextManager class for per-user project tracking 100
path provides exports
tests/test_user_context.py Tests for UserContextManager
TestUserContextManager
TestAtomicWrites
TestMultiUser
from to via pattern
src/gsd_openclaw/user_context.py ~/gsd-workspaces/.users/{user_id}/context.json atomic write pattern (tempfile + os.replace) tempfile.mkstemp|os.replace
Create UserContextManager class for per-user project context tracking with atomic persistence.

Purpose: Enable users to have persistent project context across chat sessions, supporting the /gsd:use command requirement.

Output: UserContextManager class with load/save operations, atomic writes, and multi-user isolation.

<execution_context> @/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md @/home/starmen1265/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/04-gsd-integration/04-CONTEXT.md @.planning/phases/04-gsd-integration/04-RESEARCH.md

From src/gsd_openclaw/state_manager.py (atomic write pattern to follow):

def save_state(state: SessionState, state_path: Path) -> None:
    """Save session state to file atomically with backup rotation."""
    # 1. Create parent directories if missing
    state_path.parent.mkdir(parents=True, exist_ok=True)
    # 2. Rotate backup
    # 3. Write to temp file in same directory
    fd, temp_path = tempfile.mkstemp(dir=state_path.parent, suffix='.tmp')
    # 4. Atomic replace
    os.replace(temp_path, state_path)

From src/gsd_openclaw/response_formatter.py:

@dataclass
class CardButton:
    """Interactive button for Feishu Card actions."""
    text: str
    value: Dict[str, Any]
    button_type: str = "primary"  # primary, default, danger

User context storage location (from CONTEXT.md):

  • Location: ~/gsd-workspaces/.users/{user_id}/context.json
  • Format: JSON, atomic writes (same as Phase 1 state.json)

User context data structure (from CONTEXT.md):

  • current_project: str - User's current project
  • recent_projects: List[str] - Recent 5 projects
  • last_active_at: str - ISO timestamp
  • preferences: dict - Optional settings
Task 1: Write UserContext dataclass and UserContextManager interface src/gsd_openclaw/user_context.py, tests/test_user_context.py - Test 1: UserContext can be created with all fields (user_id, current_project, recent_projects, last_active_at, preferences) - Test 2: UserContext.to_dict() returns complete dict with all fields - Test 3: UserContext.from_dict() reconstructs from dict, ignoring unknown fields - Test 4: UserContextManager.__init__ sets users_root and creates context_path correctly - Test 5: UserContextManager.load() returns None for new users (no existing context) - Test 6: UserContextManager.load() returns UserContext for existing context file Create UserContext dataclass and UserContextManager class skeleton in src/gsd_openclaw/user_context.py:
  1. Create UserContext dataclass with fields:

    • schema_version: str = "1.0"
    • user_id: str = ""
    • current_project: str = ""
    • recent_projects: List[str] = field(default_factory=list)
    • last_active_at: str = ""
    • preferences: dict = field(default_factory=dict)
  2. Add to_dict() and from_dict() methods (follow SessionState pattern exactly)

  3. Create UserContextManager class:

    • USERS_ROOT = Path.home() / "gsd-workspaces" / ".users"
    • init(self, user_id: str, users_root: Optional[Path] = None)
    • context_path property: users_root / user_id / "context.json"
    • load() -> Optional[UserContext] method
    • save(context: UserContext) -> None method (stub for next task)
  4. Create tests/test_user_context.py with TestUserContextManager class

  5. Follow state_manager.py patterns exactly for consistency pytest tests/test_user_context.py -x -v UserContext dataclass and UserContextManager skeleton exist with passing tests

Task 2: Implement atomic save with backup rotation src/gsd_openclaw/user_context.py, tests/test_user_context.py - Test 1: save() creates file atomically (no temp files remain after save) - Test 2: save() creates parent directories if missing - Test 3: save() rotates backup (context.json -> context.json.bak) - Test 4: save() overwrites old backup on subsequent saves - Test 5: save/load roundtrip preserves all data - Test 6: load() falls back to backup when main file is corrupted Implement UserContextManager.save() with atomic write pattern:
  1. Follow state_manager.py save_state() pattern exactly:

    • Create parent directories: context_path.parent.mkdir(parents=True, exist_ok=True)
    • Rotate backup: if context_path exists, rename to context.json.bak
    • Write to temp file: tempfile.mkstemp(dir=context_path.parent, suffix='.tmp')
    • Atomic replace: os.replace(temp_path, context_path)
    • Exception handling: clean up temp file on failure
  2. Add TestAtomicWrites class to tests/test_user_context.py with tests for:

    • Atomic file creation
    • Parent directory creation
    • Backup rotation
    • Cleanup on failure
  3. Ensure load() has backup fallback (same as load_state in state_manager.py)

  4. Add imports: tempfile, os, json pytest tests/test_user_context.py::TestAtomicWrites -x -v UserContextManager.save() implements atomic writes with backup rotation, matching state_manager.py pattern

Task 3: Implement multi-user isolation and convenience methods src/gsd_openclaw/user_context.py, tests/test_user_context.py, tests/conftest.py, src/gsd_openclaw/__init__.py - Test 1: Two users have completely isolated context files - Test 2: get_current_project() returns current_project or None - Test 3: set_current_project() updates current_project and adds to recent_projects - Test 4: set_current_project() maintains only last 5 recent projects - Test 5: get_recent_projects() returns list of recent projects - Test 6: New user gets default context created on first access Add convenience methods and multi-user support:
  1. Add to UserContextManager:

    • get_current_project() -> Optional[str]: Returns current_project or None
    • set_current_project(project: str) -> None:
      • Creates default context if none exists
      • Updates current_project
      • Adds to recent_projects (max 5, remove oldest if needed)
      • Updates last_active_at to now
      • Calls save()
    • get_recent_projects() -> List[str]: Returns recent_projects list
    • create_default_context() -> UserContext: Creates new context with defaults
  2. Add TestMultiUser class to tests/test_user_context.py:

    • Test isolated context paths for different users
    • Test changes to one user don't affect another
  3. Add fixtures to tests/conftest.py:

    • tmp_users_root(tmp_path): Temp directory for user contexts
    • user_context_manager(tmp_users_root): UserContextManager with temp root
  4. Update src/gsd_openclaw/__init__.py:

    • Add: from gsd_openclaw.user_context import UserContext, UserContextManager
    • Add to all: "UserContext", "UserContextManager" pytest tests/test_user_context.py::TestMultiUser tests/test_user_context.py::TestUserContextManager -x -v UserContextManager has convenience methods, multi-user isolation works, exports added to __init__.py
- All tests in tests/test_user_context.py pass - UserContext follows SessionState pattern for consistency - Atomic write pattern matches state_manager.py exactly - Multi-user isolation verified through tests

<success_criteria>

  • UserContextManager class exists with load/save/get_current_project/set_current_project methods
  • Atomic writes with backup rotation work correctly
  • Multi-user isolation verified by tests
  • Exports added to __init__.py </success_criteria>
After completion, create `.planning/phases/04-gsd-integration/04-01-SUMMARY.md`