Skip to content

dlt profile command should always be available with guidance when workspace is not initialized #3788

@elviskahoro

Description

@elviskahoro

Problem

dlt profile is a plugin-injected CLI command that only appears when a WorkspaceRunContext or ProjectRunContext is active. Without .dlt/.workspace (or dlt.yml), the command is completely absent from dlt --help and returns "invalid choice" when invoked directly.

This means users and AI agents that read the docs or rules referencing dlt profile <name> pin have no way to discover why the command doesn't exist or how to enable it. The command simply vanishes.

Current behavior

$ dlt --help
# profile not listed in Available Subcommands

$ dlt profile list
dlt: error: argument command: invalid choice: 'profile'

How the plugin chain works

  1. dlt._workspace.cli._plugins.plug_cli_profile returns ProfileCommand only when is_workspace_active() is True
  2. is_workspace_active() checks run_context.__class__.__name__ == "WorkspaceRunContext"
  3. WorkspaceRunContext is only created when .dlt/.workspace exists (checked by is_workspace_dir() in dlt/_workspace/_plugins.py)
  4. Without that file, the context falls back to plain RunContext, both guards return None, and argparse never learns about profile

The dlthub package has a parallel path via ProjectRunContext (requires dlt.yml), but the result is the same: no project/workspace marker = no command.

Expected behavior

dlt profile should always be registered as a CLI command. When workspace context is not active, it should print a helpful message instead of not existing:

$ dlt profile list

Profiles require an initialized workspace.
Create .dlt/.workspace to enable profile support:

  touch .dlt/.workspace

Then run `dlt profile list` again to see available profiles.
See https://dlthub.com/docs/hub/core-concepts/profiles-dlthub.md

This is the same pattern used for other gated features (e.g., _PondCommand returns "Please install dlthub[cache] to enable transformations" rather than hiding the command entirely).

Why this matters

  • Discoverability: Docs and AI agent rules reference dlt profile <name> pin. When the command doesn't exist, there's no breadcrumb to follow.
  • AI agents: Agents that run dlt --help to discover available commands will never find profile and cannot self-correct without this guidance.
  • Silent config failures: Profile-scoped files like dev.config.toml are silently ignored without workspace context, and without dlt profile existing, there's no command to even diagnose the problem.

Suggested fix

In dlt._workspace.cli._plugins.plug_cli_profile, always return a command class. When is_workspace_active() is False, return a placeholder that prints setup instructions (similar to the existing _PondCommand / _CacheCommand pattern already used in dlthub.project.cli._plugins):

@plugins.hookimpl(specname="plug_cli")
def plug_cli_profile() -> Type[plugins.SupportsCliCommand]:
    if is_workspace_active():
        from dlt._workspace.cli.commands import ProfileCommand
        return ProfileCommand
    else:
        class _ProfilePlaceholder(SupportsCliCommand):
            command = "profile"
            help_string = "Manage workspace profiles (requires .dlt/.workspace)"
            def execute(self, args):
                echo.echo("Profiles require an initialized workspace.")
                echo.echo("Run: touch .dlt/.workspace")
        return _ProfilePlaceholder

Environment

  • dlt version: 1.24.0
  • dlthub version: 0.22.1
  • Python: 3.13
  • OS: macOS

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions