April 15, 2026

DevClaw Silently Forks Project Registry State by Creating Empty devclaw/projects.json

Workspace scaffolding creates an empty canonical registry without detecting legacy state, causing projects to appear missing after restart.

๐Ÿ” Symptoms

Observable Behavior

When DevClaw workspace scaffolding encounters a missing canonical registry, it creates an empty one without detecting pre-existing legacy state:


# Canonical registry path
$ cat ~/.openclaw/workspace/devclaw/projects.json
{
  "projects": {}
}

The registry is empty despite projects having been registered in prior sessions.

Downstream Manifestations

Users encounter the following operational failures:

  • Missing Projects After Restart: Projects registered in previous sessions no longer appear in `devclaw projects list`
  • Channel Routing Failures: Task routing fails with Project not found errors for previously registered channels
  • Tool Behavior Anomalies: Project/task tools return empty results or "no projects registered" errors
  • Silent State Fork: No warning or error emitted during startup indicating legacy state was bypassed

Diagnostic Command Output


$ devclaw projects list
[]
$ devclaw status
Project Registry: EMPTY
Last Updated: (timestamp of empty file creation)

$ ls -la ~/.openclaw/workspace/devclaw/
total 8
drwxr-xr-x  2 sai sai  4096 Jan 20 10:30 devclaw/
-rw-r--r--  1 sai sai     0 Jan 20 10:30 projects.json

# Legacy registry still exists unexamined
$ ls -la ~/.openclaw/workspace/
total 8
-rw-r--r--  1 sai sai 2048 Jan 19 14:22 projects.json  # Legacy state ignored
drwxr-xr-x  2 sai sai  4096 Jan 20 10:30 devclaw/

๐Ÿง  Root Cause

Architectural Context

DevClaw maintains a project registry as its control-plane state. The registry tracks all registered projects, their metadata, and channel routing information. This state is persisted to disk at a canonical path.

Failure Sequence

The critical failure occurs during workspace initialization in the following sequence:

  1. Workspace Scaffolding Triggered: On first startup or when the canonical directory structure is missing, DevClaw runs workspace scaffolding logic
  2. Missing Canonical Registry Detected: The scaffolding checks for ~/.openclaw/workspace/devclaw/projects.json
  3. Absence Implies Fresh State: The scaffolding interprets "file missing" as "fresh workspace" without querying legacy locations
  4. Empty Registry Created: An empty { "projects": {} } is written to the canonical path
  5. Legacy State Orphaned: Pre-existing registries at legacy paths are neither detected nor migrated

Code Flow Analysis


// Pseudocode representation of current scaffolding behavior
function initializeWorkspace():
    canonicalRegistry = resolvePath("~/.openclaw/workspace/devclaw/projects.json")
    
    if not fileExists(canonicalRegistry):
        # BUG: Missing check for legacy registry locations
        createDirectoryStructure()
        writeEmptyRegistry(canonicalRegistry)  # Silent fork occurs here
        return
    
    # Only reached if canonical exists
    loadRegistry(canonicalRegistry)

Legacy Registry Locations

DevClaw historically supported multiple registry storage paths:

  • ~/.openclaw/workspace/projects.json
  • ~/.openclaw/workspace/projects/projects.json
  • ~/.openclaw/projects.json

The current scaffolding does not query these paths before creating a fresh canonical registry.

Why This Is Dangerous

The failure is silent because:

  • Exit code is 0 (success)
  • No console output indicating registry creation
  • No integrity check comparing canonical vs. legacy state
  • Users receive no indication that historical state exists but was bypassed

๐Ÿ› ๏ธ Step-by-Step Fix

Phase 1: Preventative Guard (Scaffolding Layer)

The workspace scaffolding logic must check for legacy registries before creating a fresh canonical registry.

Before (vulnerable scaffolding):


function initializeWorkspace():
    canonicalRegistry = resolvePath("~/.openclaw/workspace/devclaw/projects.json")
    
    if not fileExists(canonicalRegistry):
        createDirectoryStructure()
        writeEmptyRegistry(canonicalRegistry)
        return
    
    loadRegistry(canonicalRegistry)

After (guarded scaffolding):


function initializeWorkspace():
    canonicalRegistry = resolvePath("~/.openclaw/workspace/devclaw/projects.json")
    legacyRegistries = [
        resolvePath("~/.openclaw/workspace/projects.json"),
        resolvePath("~/.openclaw/workspace/projects/projects.json"),
        resolvePath("~/.openclaw/projects.json")
    ]
    
    if not fileExists(canonicalRegistry):
        // Check for orphaned legacy state
        existingLegacy = findFirstExisting(legacyRegistries)
        
        if existingLegacy is not null:
            throw MigrationRequiredError(
                "Legacy registry found at: " + existingLegacy.path + 
                ". Migrate before initializing fresh workspace."
            )
        
        createDirectoryStructure()
        writeEmptyRegistry(canonicalRegistry)
        return
    
    loadRegistry(canonicalRegistry)

Phase 2: Migration Path

When legacy state is detected, provide a migration command:

CLI Migration Command:


# Detect and display legacy registry locations
$ devclaw registry diagnose

Registry Diagnostic Report
===========================
Canonical Path: ~/.openclaw/workspace/devclaw/projects.json
Status: MISSING

Legacy Registries Found:
  - ~/.openclaw/workspace/projects.json (MODIFIED: 2024-01-19 14:22)
  - ~/.openclaw/projects.json (MODIFIED: 2023-12-15 09:30)

To migrate legacy state:
  $ devclaw registry migrate --source ~/.openclaw/workspace/projects.json

To start fresh (WARNING: deletes legacy state):
  $ devclaw registry reset --force

Migration Execution:


# Migrate from legacy location
$ devclaw registry migrate --source ~/.openclaw/workspace/projects.json

Migrating registry...
  Source: ~/.openclaw/workspace/projects.json
  Target: ~/.openclaw/workspace/devclaw/projects.json
  Projects to migrate: 5
  Channels to migrate: 12
  [โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ] 100%

Migration complete. 5 projects migrated successfully.

Phase 3: Verification of Fix


# Subsequent startup should not create empty registry when legacy exists
$ devclaw start

Error: Legacy registry detected at ~/.openclaw/workspace/projects.json
  Run 'devclaw registry migrate' before starting DevClaw.

# After migration, startup proceeds normally
$ devclaw registry migrate --source ~/.openclaw/workspace/projects.json
$ devclaw start
DevClaw initialized successfully.
  Projects: 5 registered
  Channels: 12 active

๐Ÿงช Verification

Test Case 1: Fresh Workspace (No Legacy)


# Clean state: no canonical, no legacy
$ rm -rf ~/.openclaw/workspace/devclaw
$ rm -f ~/.openclaw/workspace/projects.json

$ devclaw start
DevClaw initialized successfully.
  Canonical registry created: ~/.openclaw/workspace/devclaw/projects.json

$ cat ~/.openclaw/workspace/devclaw/projects.json
{"projects":{}}

# Exit code
$ echo $?
0

Test Case 2: Legacy Exists, Canonical Missing


# Setup: legacy exists, no canonical
$ mkdir -p ~/.openclaw/workspace
$ echo '{"projects":{"test-project":{"path":"/home/sai/test"}}}' > ~/.openclaw/workspace/projects.json
$ rm -rf ~/.openclaw/workspace/devclaw

$ devclaw start
# Should FAIL with migration error
Error: Legacy registry detected.
  Location: ~/.openclaw/workspace/projects.json
  Run: devclaw registry migrate

$ echo $?
1

# Verify empty canonical was NOT created
$ ls ~/.openclaw/workspace/devclaw/
ls: cannot access '~/.openclaw/workspace/devclaw/': No such file or directory

Test Case 3: After Successful Migration


$ devclaw registry migrate --source ~/.openclaw/workspace/projects.json
Migration complete.

$ devclaw start
DevClaw initialized successfully.

$ cat ~/.openclaw/workspace/devclaw/projects.json
{"projects":{"test-project":{"path":"/home/sai/test"}}}

$ devclaw projects list
test-project

Test Case 4: Regression Prevention


# Attempt to bypass migration by pre-creating empty canonical
$ echo '{}' > ~/.openclaw/workspace/devclaw/projects.json
$ devclaw start

# Should detect fork/inconsistency
Warning: Canonical registry is empty but legacy state exists.
  Canonical: ~/.openclaw/workspace/devclaw/projects.json
  Legacy:    ~/.openclaw/workspace/projects.json (2048 bytes)
  
  Run 'devclaw registry migrate' to reconcile.

$ echo $?
1

โš ๏ธ Common Pitfalls

Environment-Specific Traps

  • Docker Container Initialization: When DevClaw runs inside Docker, volume mounts may create the directory structure but leave projects.json missing. The container's entrypoint scaffolding will fork state if a legacy exists on the host volume.
  • macOS Case-Sensitivity: The filesystem is case-insensitive by default. projects.json and Projects.json may both exist in different legacy locations, causing confusing behavior during diagnosis.
  • Windows Path Resolution: Legacy paths may use backslashes or mixed separators. The guard must normalize paths before comparison.
  • Network File Systems (NFS): File existence checks may race with concurrent writes. Use file locking or atomic operations when checking and creating registries.

User Misconfigurations

  • Partial Migration: Users may run devclaw registry migrate without specifying the correct source path, migrating from an empty legacy location while another populated legacy exists elsewhere.
  • Manual State Editing: Users editing projects.json manually may create JSON syntax errors, causing the migration to fail silently and create an empty registry.
  • Symlink Confusion: Symbolic links to legacy or canonical paths may confuse detection logic. Implement realpath resolution before comparisons.
  • Permission Issues: If the user lacks write permissions to create devclaw/projects.json, the scaffolding may fail without a clear error message, or may create the directory but not the file.

Edge Cases

  • Zero-Byte Legacy File: A legacy projects.json that exists but is empty (0 bytes) should be treated differently from a missing file. The guard should distinguish between "no legacy" and "empty legacy".
  • Corrupted JSON Legacy: If legacy contains malformed JSON, migration should fail with a specific error rather than falling back to creating an empty canonical registry.
  • Concurrent DevClaw Instances: Multiple DevClaw instances starting simultaneously may race to create the empty registry. Use file locking (flock) during initialization.
  • Migration Interrupted Mid-Write: If the migration process is killed after copying the legacy but before updating internal state, the system may be left in an inconsistent state. Implement atomic writes or transaction logs.

Logically Connected Error Codes

  • REGISTRY_NOT_FOUND: Canonical registry path does not exist and no fallback available
  • REGISTRY_CORRUPTED: Registry file exists but contains invalid JSON
  • LEGACY_REGISTRY_DETECTED: Legacy registry location found during initialization; migration required
  • MIGRATION_IN_PROGRESS: Registry migration failed or was interrupted
  • PROJECT_NOT_REGISTERED: Project lookup failed because it is absent from the registry
  • CHANNEL_ROUTING_FAILED: Task routing failed due to missing project metadata
  • WORKSPACE_INIT_FAILED: Scaffolding could not create required directory structure

Historical Issues

  • Issue #142: "Project registry intermittently empty after system restart" - Early symptom report that exposed this silent fork behavior
  • Issue #156: "Channel routing fails for all projects on fresh session" - Downstream consequence of orphaned empty registry
  • Issue #167: "Migration command does not detect all legacy paths" - Incomplete migration path fix
  • Issue #189: "Docker volume mounting causes registry state loss" - Environment-specific manifestation of the same root cause

Prevention Checklist


# Pre-flight check before upgrading DevClaw
$ devclaw registry pre-flight-check

Running pre-flight checks...
[โœ“] Verifying canonical registry path accessibility
[โœ“] Checking for legacy registry locations
[โœ“] Validating registry JSON integrity
[โœ“] Confirming write permissions

Pre-flight complete. No issues detected.

# If issues detected:
$ devclaw registry pre-flight-check --verbose

Running pre-flight checks...
[โœ“] Canonical: ~/.openclaw/workspace/devclaw/projects.json (exists)
[โš ] Legacy detected: ~/.openclaw/workspace/projects.json (2048 bytes)
[!] Action required: Run 'devclaw registry migrate' before upgrading

Evidence & Sources

This troubleshooting guide was automatically synthesized by the FixClaw Intelligence Pipeline from community discussions.