Skip to content

Latest commit

 

History

76 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ProfileDock

ProfileDock is a lightweight command-line tool for managing isolated, persistent Chromium profiles. Every profile receives a separate browser data directory, so cookies, sessions, local storage, cache, login state, and browsing data do not leak into another ProfileDock profile.

Current release: 0.8.0

Features

  • Create, list, launch, close, and delete browser profiles.
  • Keep browser state between launches with Playwright persistent contexts.
  • Open an exact number of blank tabs.
  • Prevent the same profile from launching twice.
  • Close browsers gracefully through a local controller process.
  • Use Playwright Chromium or fall back to an installed Chrome or Chromium executable.
  • Store ProfileDock data in the operating system's application-data directory.
  • Override storage with --data-root or PROFILEDOCK_DATA_ROOT.

Requirements

  • Python 3.9 or newer.
  • Windows, macOS, or Linux.
  • Internet access during the initial dependency installation.
  • Google Chrome or access to Playwright's Chromium download service.

Git is optional for running ProfileDock but required when cloning or updating the repository with Git.

Automated setup

Open a terminal in the project directory and run:

python scripts/setup_project.py

The setup script:

  1. Creates an isolated .venv environment if one does not exist.
  2. Upgrades pip inside that environment.
  3. Installs ProfileDock and its test dependencies from requirements.txt.
  4. Uses installed Google Chrome or installs Playwright Chromium.
  5. Runs the complete test suite.

The script is safe to run again after pulling updates. It reuses the existing virtual environment.

Setup does not create or remove ProfileDock application data. The data root is resolved when a profiledock command runs.

To skip all browser preparation:

python scripts/setup_project.py --skip-browser

Use --skip-browser only when a compatible browser is already available or when you only need to run non-browser functionality.

Manual setup

Windows PowerShell

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m playwright install chromium

If Playwright's Chromium download is blocked but Chrome or Chromium is installed, omit the final command. ProfileDock tries the installed Chrome channel and then a detected system browser executable.

macOS and Linux

python3 -m venv .venv
./.venv/bin/python -m pip install --upgrade pip
./.venv/bin/python -m pip install -r requirements.txt
./.venv/bin/python -m playwright install chromium

Using the virtual environment

Activation is optional. You can run ProfileDock directly through the isolated environment.

Windows PowerShell:

.\.venv\Scripts\profiledock.exe --help

macOS and Linux:

./.venv/bin/profiledock --help

To activate the environment on Windows PowerShell:

.\.venv\Scripts\Activate.ps1

If PowerShell blocks activation, either run the executable directly or temporarily allow local scripts for the current terminal:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\Activate.ps1

To activate on macOS or Linux:

source .venv/bin/activate

After activation, the profiledock command is available directly.

First profile walkthrough

By default, ProfileDock uses %LOCALAPPDATA%\ProfileDock on Windows, ~/Library/Application Support/ProfileDock on macOS, and ${XDG_DATA_HOME:-~/.local/share}/profiledock on Linux.

To use another location for one invocation, place the global option before the command:

profiledock --data-root /path/to/profiledock-data list

To use another location for every command in the current environment, set PROFILEDOCK_DATA_ROOT. The CLI option takes precedence over the environment variable, and the environment variable takes precedence over the platform default.

Create a profile:

profiledock create "Personal"

List profiles and copy the generated ID:

profiledock list

Launch the profile and answer the tab-count prompt:

profiledock launch <id>

You can provide the tab count without a prompt:

profiledock launch <id> --tabs 5

Browse and sign in manually. ProfileDock does not automate login or collect passwords.

Close the browser gracefully:

profiledock close <id>

Launch the same ID again to restore its persistent browser state:

profiledock launch <id>

Commands

Commands that operate on a single profile accept a profile identifier. The identifier can be a full ID, a unique ID prefix, or an exact profile name. Matching is case-sensitive for both IDs and names. If the input matches more than one profile, ProfileDock prints the matching IDs and names and exits without taking action.

Version

profiledock --version

Displays the current version of ProfileDock.

Create

profiledock create "Profile name"

Creates profile metadata and a dedicated browser data directory.

List

profiledock list
profiledock list --json

Displays each profile's ID, name, and status in a formatted table, or outputs JSON with --json.

Show

profiledock show <id-or-name>
profiledock show <id-or-name> --json

Displays all safe profile metadata (ID, name, status, created at, data directory, and last launched timestamp). Controller authentication tokens are never displayed.

Rename

profiledock rename <id-or-name> "New name"

Validates the new non-empty name and renames the profile atomically.

Status

profiledock status
profiledock status <id-or-name>
profiledock status --json
profiledock status <id-or-name> --json

Reports profile status (stopped, starting, running, closing, stale, or error where detectable). When invoked without an identifier, status reports across all profiles.

Exit codes:

ProfileDock uses stable exit codes for scripting compatibility:

Code Meaning
0 Success
1 User error (profile not found, validation error, profile already running, etc.)
2 Reserved for system errors (optional, not currently used)

Launch

profiledock launch <id-or-name>
profiledock launch <id-or-name> --tabs 3

Starts a persistent browser context with exactly the requested number of about:blank tabs. A running profile cannot be launched a second time.

Close

profiledock close <id-or-name>

Requests graceful browser shutdown and removes the profile's running-state file.

If the entire browser is closed manually or exits unexpectedly, the controller detects the closure, exits, and removes its running state. The profile can then be launched again normally.

Delete

profiledock delete <id-or-name>

Asks for confirmation, then permanently removes the profile metadata and browser data. A running profile must be closed before deletion. The profile directory is quarantined during the metadata update and restored if that update fails.

For non-interactive use:

profiledock delete <id-or-name> --yes

Doctor

profiledock doctor
profiledock doctor --json
profiledock doctor --repair

Performs comprehensive diagnostic checks across the environment and profile storage.

Diagnostic checks:

  • python_version: Verifies Python is >= 3.9.
  • writable_data_root: Checks that the application-data directory is writable.
  • metadata_schema: Validates the profiles.json schema (version 1) and contents.
  • metadata_backup_state: Inspects the backup file (profiles.json.bak) for validity.
  • profile_directories_exist: Ensures every configured profile has a corresponding browser-data directory.
  • profile_paths_under_data_root: Validates that all profile data paths reside safely within the profile root boundary.
  • playwright_package: Checks if the playwright Python package is installed.
  • playwright_chromium: Verifies if Playwright Chromium browser executable is installed.
  • system_chrome: Verifies if system Google Chrome or Chromium is available as fallback.
  • browser_availability: Aggregate check verifying that at least one usable browser engine is present.
  • runtime_permissions: Checks read/write permissions on the runtime/ directory.
  • stale_running_state: Detects leftover running.json state files from terminated processes.
  • orphan_profile_directories: Identifies folders in profiles/ that are not listed in metadata.
  • version_consistency: Verifies that the runtime version matches installed package metadata.

Repair capabilities (--repair):

  • Cleans up stale runtime running.json files automatically.
  • Recovers valid metadata from profiles.json.bak if profiles.json is missing or corrupted.
  • Automatically migrates legacy bare-array format metadata to versioned schema.
  • Never deletes browser data directories automatically.
  • Never reattaches orphan profile directories without manual user confirmation.

Exit codes:

Exits with 0 when all critical checks pass (including with warnings). Exits with 1 if any check fails (FAILED status).

Migrate

profiledock migrate --from-project <path>
profiledock migrate --from-project <path> --json
profiledock migrate --from-project <path> --remove-source --yes

Migrates profiles and browser data from a legacy or another project directory into the active ProfileDock data root.

Migration safety & guarantees:

  • Pre-migration backup: It is strongly recommended to create a copy/backup of both the source directory and the destination data root before initiating migration.
  • Safety checks: Detects legacy profiles.json and profiles/, validates metadata schema, and refuses migration if any source profile is currently running.
  • Conflict detection: Prevents silent overwrite by detecting ID or name conflicts.
  • Atomic directory copying: Copies profile directories into temporary destination folders, verifies file integrity, and moves them into place atomically before updating metadata.
  • Automatic rollback: Incomplete changes in the destination are rolled back cleanly if copying or validation fails.
  • Source preservation: Leaves source files completely untouched by default. --remove-source deletes source data only after successful migration and explicit confirmation.
  • Idempotent: Re-running migration safely skips already migrated identical profiles.

Data storage and persistence

ProfileDock resolves one data root for each command and uses this structure:

ProfileDock/
├── metadata/
│   ├── profiles.json
│   └── profiles.lock
├── backups/
│   └── profiles.json.bak
├── profiles/
│   └── <profile-id>/
│       └── browser-data/
├── runtime/
│   └── <profile-id>/
│       ├── running.json
│       └── controller.error
└── logs/

Metadata document format

profiles.json contains a versioned metadata document:

{
  "schema_version": 1,
  "profiles": [
    {
      "id": "abc123",
      "name": "Personal",
      "created_at": "2024-01-15T10:30:00+00:00",
      "data_dir": "/path/to/profiles/abc123/browser-data",
      "last_launched_at": null
    }
  ]
}

The metadata document includes:

  • schema_version: Version of the metadata format (currently 1)
  • profiles: Array of profile objects with required fields: id, name, created_at, data_dir
  • Optional field: last_launched_at (ISO-8601 timestamp)

Metadata migration

ProfileDock automatically migrates older bare-array format to the versioned document format:

  • The old profiles.json is backed up to profiles.json.bak before migration
  • Migration validates all profile data before accepting the new format
  • Invalid data is rejected before any changes are written

Metadata safety

ProfileDock implements several safety mechanisms to protect metadata integrity:

Atomic writes: Metadata, backups, and controller state use unique temporary files and atomic replacement. Transient Windows sharing violations are retried within a bounded interval.

Cross-process locking: A lock file (metadata/profiles.lock) coordinates concurrent metadata modifications through an operating-system file lock. Its presence alone does not mean ProfileDock is locked.

Backup recovery: Before each metadata update, the current file is backed up to profiles.json.bak. The profiledock doctor --repair command can restore a valid backup after primary-file corruption.

Duplicate prevention: Profile IDs and data directories must be unique. Duplicate values are rejected before any changes are written.

Path safety: Data directories must exactly match profiles/<id>/browser-data. Symlinks, junctions, reparse points, duplicate paths, and path traversal attempts are rejected.

Managed-directory safety: ProfileDock rejects unsafe managed directories, path-like profile IDs, runtime paths beneath browser-data, and deletion targets that do not exactly match profiles/<id>/browser-data.

Private storage: On POSIX systems, ProfileDock restricts managed directories to the owner and writes metadata, lock, controller-state, and controller-error files with owner-only permissions. Windows access remains governed by the directory's inherited ACLs.

Corruption handling: ProfileDock never overwrites corrupted metadata automatically. If both the primary and backup files are corrupted, manual intervention is required.

profiles.json contains profile metadata only. Chromium stores cookies, local storage, cache, sessions, and login state inside browser-data.

running.json exists only while a profile controller is active. New state files use a versioned local protocol and contain the profile ID, controller PID, start time, loopback port, status, and a random authentication token. State writes are atomic, and the controller accepts a close request only when its token matches. Stale state files are cleaned automatically.

Runtime state, logs, backups, metadata, and browser data are separated. Runtime files are never written inside browser-data.

Isolation, security, and privacy

  • Every profile uses a separate Chromium user data directory.
  • ProfileDock does not automate authentication or store passwords itself.
  • Websites and Chromium may store credentials, cookies, tokens, and browsing history inside browser-data.
  • Anyone with access to a profile directory may be able to access its browser state.
  • Keep the selected data root private and out of source control.
  • Closing a profile does not delete its browsing data.
  • Deleting a profile permanently removes its local browser data.

Testing

Windows:

.\.venv\Scripts\python.exe -m pytest

macOS and Linux:

./.venv/bin/python -m pytest

The integration test launches a real persistent browser context, verifies the requested tab count, closes it, relaunches it, and confirms that a persistent cookie remains. It uses Playwright Chromium or installed Google Chrome and skips only when neither is available.

Run only fast unit tests:

.\.venv\Scripts\python.exe -m pytest -m "not browser"

Run only browser and controller integration tests:

.\.venv\Scripts\python.exe -m pytest -m browser

JSON output format

All JSON output from --json flags is stable and safe for scripting:

list --json and status --json:

Always returns an array of profile objects:

[
  {
    "id": "abc123",
    "name": "Work",
    "status": "stopped",
    "created_at": "2026-01-01T00:00:00+00:00",
    "data_dir": "/path/to/profiles/abc123/browser-data",
    "last_launched_at": null
  }
]

show <profile> --json:

Returns a single profile object with all metadata:

{
  "id": "abc123",
  "name": "Work",
  "status": "running",
  "created_at": "2026-01-01T00:00:00+00:00",
  "data_dir": "/path/to/profiles/abc123/browser-data",
  "last_launched_at": "2026-01-15T12:30:00+00:00"
}

doctor --json:

Returns diagnostic checks, repairs performed, and overall health status:

{
  "checks": [
    {
      "id": "python_version",
      "status": "ok",
      "summary": "Python version is 3.11.0 (>= 3.9 required)."
    },
    {
      "id": "stale_running_state",
      "status": "warning",
      "summary": "Found 1 stale running.json file(s).",
      "action": "Run 'profiledock doctor --repair' to clean stale running-state files."
    }
  ],
  "repairs": [
    {
      "id": "repair_stale_running_state",
      "status": "ok",
      "summary": "Cleaned up 1 stale running.json file(s)."
    }
  ],
  "healthy": true
}

migrate --json:

Returns details of migrated, skipped, and failed profiles:

{
  "source_root": "/path/to/source",
  "destination_root": "/path/to/destination",
  "migrated": [
    {
      "id": "abc123",
      "name": "Work",
      "status": "migrated",
      "message": "successfully migrated"
    }
  ],
  "skipped": [],
  "failed": [],
  "source_removed": false
}

Guarantees:

  • JSON output is always valid and parseable
  • No human prose mixed with JSON
  • No sensitive data exposed (tokens, secrets, passwords)
  • Field names and types are stable across versions
  • status and list always return arrays for consistent scripting
  • Timestamps use ISO-8601 format with a timezone offset when present

Updating the project

If the project was cloned with Git:

git pull
python scripts/setup_project.py

Rerunning setup updates the editable installation and executes the tests. Review the current version in pyproject.toml, profiledock.__version__, or the release tag.

Troubleshooting

Chromium download returns HTTP 403

Playwright's CDN may be unavailable in some locations. Install Chrome or Chromium and rerun setup. The script detects supported system browsers and avoids the blocked download.

profiledock is not recognized

Activate .venv, or run the executable using its full project-local path:

.\.venv\Scripts\profiledock.exe --help

Profile is already running

Close it normally:

profiledock close <id>

If the browser or controller stopped unexpectedly, run profiledock list. ProfileDock detects dead controller processes and cleans stale running state.

Profile data directory is missing

The profile metadata exists but its browser-data directory was moved or deleted. Restore the directory from a backup or delete and recreate the affected profile.

profiles.json is corrupted

Run profiledock doctor --repair to validate and restore profiles.json.bak. If both files are corrupted, restore from a manual backup. Normal profile commands intentionally refuse to overwrite corrupted metadata automatically.

profiles.lock exists but no process is running

This is normal. ProfileDock uses an operating-system lock on this file, so an unlocked file may remain on disk safely. Do not use file existence to decide whether a metadata operation is active.

Controller launch failure

When profiledock launch fails, the CLI now shows a specific error message instead of a generic failure. Common causes and fixes:

Playwright package not installed:

Error: No module named 'playwright'

Rerun project setup with python scripts/setup_project.py, or install Playwright through the active virtual environment.

No supported browser found:

Error: Playwright Chromium: <error>\nGoogle Chrome: <error>\nSystem browser: <error or not found>

Either install Playwright Chromium (playwright install chromium) or install Chrome or Chromium on your system.

Browser process failed to launch: The error message will include Playwright's diagnostic details. Check that the profile data directory exists and is accessible.

Controller startup timed out: The browser took longer than 30 seconds to become ready. Check system resources and close other applications.

Controller process exited unexpectedly: The controller subprocess crashed. Check for system resource constraints or permission issues.

When a controller fails, ProfileDock preserves a diagnostic file at runtime/<id>/controller.error beneath the selected data root. It contains a stable error category, a bounded diagnostic message, and the browser channel attempted when relevant. Diagnostics are limited to 4 KiB, controller tokens are redacted, and the file is automatically cleaned up on the next successful launch.

Removing ProfileDock

Profile data is separate from the source project, so decide whether to keep or delete both locations.

1. Close running profiles

List profiles and close every entry marked running:

profiledock list
profiledock close <id>

2. Back up profiles if needed

To preserve login state and browser data, copy these items to a secure location:

metadata/
backups/
profiles/

They must be restored together beneath the same data root.

3. Remove Playwright-managed browsers if needed

This removes browsers installed by this Playwright environment. It does not remove system Google Chrome.

Windows:

.\.venv\Scripts\python.exe -m playwright uninstall

macOS and Linux:

./.venv/bin/python -m playwright uninstall

4. Remove only the isolated environment

Deactivate it first if active:

deactivate

Then delete the .venv directory. This removes installed Python dependencies but keeps source code and application data. The setup script can recreate it later.

5. Remove the complete project

Close all profiles, leave the project directory in your terminal, and delete the profiledock folder using File Explorer, Finder, or your desktop environment's file manager. Moving it to the Recycle Bin or Trash is recommended because it remains recoverable until emptied.

Deleting the source project does not delete ProfileDock application data. Remove the platform data root separately only after closing profiles and confirming that no browser state must be retained.

The default application-data roots are %LOCALAPPDATA%\ProfileDock on Windows, ~/Library/Application Support/ProfileDock on macOS, and ${XDG_DATA_HOME:-~/.local/share}/profiledock on Linux. If PROFILEDOCK_DATA_ROOT or --data-root was used, remove that selected directory instead. Deleting the data root permanently removes every ProfileDock profile, session, cookie, cache, backup, and runtime record stored there.

Versioning

ProfileDock follows Semantic Versioning. Stable releases use annotated Git tags such as v0.7.3.

License

ProfileDock is available under the MIT License. See LICENSE for the full terms.

About

ProfileDock is a lightweight CLI for managing isolated, persistent Chromium profiles. Each profile has its own cookies, sessions, local storage, cache, login state, and Chromium user-data directory.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages