blowhorn profile
blowhorn profile: auth, current, delete, get, list, set, status, switch.
The blowhorn profile commands. Each one's --help prints the same text.
| Command | What it does |
|---|---|
profile auth |
Refresh authentication/session state for one or more platforms. |
profile current |
Show the active profile after resolving CLI, env, and config defaults. |
profile delete |
Retire a profile by moving data/profiles/<name> -- config.yaml, data/ and every saved |
profile get |
Print one profile's settings with every secret masked: its config.yaml, with the |
profile list |
List available local profile directories. |
profile set |
Write KEY=VALUE pairs safely. |
profile status |
Report what each local profile is set up for: the platforms it holds an account |
profile switch |
Set a profile as the default profile in global config. |
blowhorn profile auth
Refresh authentication/session state for one or more platforms.
Supported platforms and authentication mechanisms:
linkedin - Persistent browser session. Automated login via LI_USERNAME / LI_PASSWORD in profile config.yaml, with fallback to manual browser entry.
x - Persistent browser session. Automated login via X_USERNAME / X_PASSWORD in profile config.yaml, with fallback to manual browser entry.
reddit - Persistent browser session. Automated login via RDDT_USERNAME / RDDT_PASSWORD in profile config.yaml, with fallback to manual browser entry.
slack - Hybrid: session credentials (xoxc token + d cookie) captured through the run's browser driver (the extension by default), saved to the profile's Slack credential in the store (never config.yaml), and reused for direct API calls. No Slack app install required. Use --workspace <host> to capture a new workspace; omit it to refresh every workspace listed under 'slack_workspaces' in that credential. Use --mode paste for the legacy OAuth-token flow.
bluesky - No browser. Logs in to Bluesky with a handle and app password -- the same login every post makes -- and stores the pair only when Bluesky accepts it, so a refused credential is never saved. For one named profile in a terminal it asks for both (the stored handle is the default; a blank app password keeps the stored one); --handle and --app-password-stdin supply them without a prompt. Otherwise the stored pair is logged in with and nothing is written.
Use --profile all to refresh every local profile after applying any --exclude filters.
With --headless the browser still opens, as a background window (Chrome is never run headless); only automated credential login is attempted and the manual browser fallback is skipped.
blowhorn profile auth [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--all |
boolean | false |
Refresh every platform 'blowhorn profile auth' can log in to (linkedin, x, reddit, slack). Supersedes --platform: when --all is set the platform is ignored, whether you typed it or inherited it from BLOWHORN_PLATFORM or defaults.platform |
--json |
boolean | false |
Emit machine-readable JSON output |
--workspace |
string | Slack only: capture session credentials for this workspace domain (e.g. 'mesheryio.slack.com'). Opens a browser window; sign in to Slack, and the xoxc token + d cookie are extracted. If omitted, all workspaces listed under 'slack_workspaces' in the profile's Slack credential in the store are refreshed. | |
--mode |
string | Slack only: 'session' (default) captures xoxc/d via browser; 'paste' prompts for a User OAuth Token (xoxp-…) - requires app install. | |
--handle |
string | Bluesky only, one named profile: the handle to log in as (alice.bsky.social; a leading @ is dropped). Stored with the app password only when Bluesky accepts the login; omit it to use the stored handle | |
--app-password-stdin |
boolean | false |
Bluesky only, one named profile: read the app password from the first line of stdin, so it never reaches argv, the daily log or a prompt. A blank line is refused and nothing is written |
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Pace of the random delays between 'blowhorn profile auth' browser steps: a preset name (fast/normal/slow) or a numeric multiplier (e.g. 0.5, 2.0). Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile auth --platform x --profile lee
blowhorn profile auth --all --profile lee
blowhorn profile auth --platform slack --profile lee --workspace mesheryio.slack.com
blowhorn profile auth --platform slack --profile lee --mode paste
blowhorn profile auth --platform linkedin --profile all --headless
blowhorn profile auth --platform bluesky --profile lee
blowhorn profile auth --platform linkedin --profile kate --headed --jsonOutput: json with --json, text otherwise.
blowhorn profile current
Show the active profile after resolving CLI, env, and config defaults.
blowhorn profile current [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile current' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile current
blowhorn profile current --config ~/.blowhorn.yamlOutput: text.
blowhorn profile delete
Retire a profile by moving data/profiles/<name> -- config.yaml, data/ and every saved browser session -- to data/profiles/.trash/<name>-<timestamp>. Nothing is ever removed: the browser sessions are the expensive part of a profile and the move keeps them recoverable. The profile's row in the store's profiles is retired first (soft-deleted, so --profile all stops reaching it); a profile the store never listed just moves. Needs the store: unreachable is exit 3 and nothing moves. Requires --yes; --dry-run shows what would move and where.
blowhorn profile delete [OPTIONS] name| Argument | Required | Description |
|---|---|---|
name |
yes | Profile name (the directory under data/profiles/) |
| Flag | Type | Default | Description |
|---|---|---|---|
--yes |
boolean | false |
Confirm the move to data/profiles/.trash/; without it the command refuses and exits 1 |
--json |
boolean | false |
Emit machine-readable JSON output |
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile delete' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile delete sam --dry-run
blowhorn profile delete sam --yes --jsonOutput: json with --json, text otherwise.
blowhorn profile get
Print one profile's settings with every secret masked: its config.yaml, with the GitHub keys (GH_*) read from its credential in the store. Keys whose names contain PASSWORD, SECRET, TOKEN or COOKIE are rendered as {"set": true} or {"set": false}; their values are never printed, in JSON or in the table. A store that cannot be reached leaves the GitHub keys out and is named on a Credentials: line.
blowhorn profile get [OPTIONS] name| Argument | Required | Description |
|---|---|---|
name |
yes | Profile name (the directory under data/profiles/) |
| Flag | Type | Default | Description |
|---|---|---|---|
--json |
boolean | false |
Emit machine-readable JSON output |
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile get' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile get kate
blowhorn profile get kate --jsonOutput: json with --json, text otherwise.
blowhorn profile list
List available local profile directories.
blowhorn profile list [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile list' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile listOutput: text.
blowhorn profile set
Write KEY=VALUE pairs safely. GitHub keys (GH_TOKEN, GH_USERNAME) are stored in the profile's GitHub credential in the store, where runs read them, and never in the file; a blank value clears a key. Every other key goes into data/profiles/<name>/config.yaml: the file is round-tripped with its key order preserved, rewritten atomically under a file lock, and only the README template keys (plus GH_USERNAME, slack_workspaces and the <WORKSPACE>SLACK* session keys) are accepted unless --allow-unknown is passed. Every refusal comes before anything is written. The output names the keys that changed and never echoes a value. Replacing a credential an API check judges (GH_TOKEN, the Bluesky handle or app password, a Slack token or captured session) sets that platform back to not checked in profile status until the next check, because each such check records which credential it judged. A browser platform's check is about its saved session and stays.
--create makes a new profile in both halves: it resolves EMAIL to the Layer5 Cloud user the profile is bound to, writes the profile's row in the store's profiles, and only then scaffolds data/profiles/<name>/config.yaml from the template plus data/ and browser/. EMAIL is required. --create needs the store: when it cannot be reached the create is refused with exit 3, nothing is written on either side and no directory is scaffolded, because a profile with no row is one no job can select. An email no Layer5 Cloud user holds, or one that several hold, is refused by name; --subject <uuid> names the user directly on those two branches, is refused when it names no live user, and is refused when EMAIL resolves to someone else. A profile is never created without a Layer5 Cloud user: there is no --force. The same email already bound to another profile, or a name held by another user's profile, is refused rather than renamed.
--register adds a profile that exists only under data/profiles/ to the store's profiles: the same resolution and refusals, no scaffold, EMAIL read from config.yaml when not given, and safe to run again.
blowhorn profile set [OPTIONS] name [assignments...]| Argument | Required | Description |
|---|---|---|
name |
yes | Profile name (the directory under data/profiles/) |
assignments ... |
no | KEY=VALUE pairs to write (slack_workspaces takes a comma-delimited list) |
| Flag | Type | Default | Description |
|---|---|---|---|
--create |
boolean | false |
Create a new profile: resolve EMAIL to its Layer5 Cloud user, write its row in the store's profiles, then scaffold data/profiles/<name>/{config.yaml,data/,browser/} from the README template; needs the store, and refuses to touch a profile that already exists |
--register |
boolean | false |
Add a profile that already exists under data/profiles/ to the store's profiles: the same resolution and refusals as --create, no scaffold, EMAIL read from config.yaml when not given, safe to run again |
--subject |
string | The Layer5 Cloud user id (a uuid) the profile is bound to, for an EMAIL no user holds or several hold; refused when it names no live user, or when EMAIL resolves to someone else | |
--allow-unknown |
boolean | false |
Accept keys outside the config.yaml template (the template keys, GH_USERNAME, slack_workspaces and <WORKSPACE>SLACK* are always accepted) |
--json |
boolean | false |
Emit machine-readable JSON output |
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile set' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile set kate EMAIL=kate@example.com X_USERNAME=katesuttons
blowhorn profile set sam --create PROFILE=sam EMAIL=sam@example.com
blowhorn profile set sam --create EMAIL=sam@example.com --subject 3f2b1c4d-8a9e-4c6b-9d1e-2a3b4c5d6e7f
blowhorn profile set sam --register
blowhorn profile set kate GH_TOKEN=ghp_yourtoken --json
blowhorn profile set lee slack_workspaces=mesheryio.slack.com,acme.slack.com
blowhorn profile set kate CUSTOM_NOTE=migrated --allow-unknownOutput: json with --json, text otherwise.
blowhorn profile status
Report what each local profile is set up for: the platforms it holds an account for (credential key names only -- values are never printed), the browser session directory and its last-modified time, whether another blowhorn process holds its lock, the last recorded session check, and whether the profile is excluded by default. No browser and no platform network by default: accounts are read from config.yaml, and GitHub's from the store, once for every profile. A store that cannot be reached leaves GitHub unknown and is named on a Credentials: line, not fatal, and a check made then skips GitHub and keeps its last recorded result.
--check-sessions runs a read-only probe per configured platform (LinkedIn, X and Reddit open the saved session in a background window and look for the signed-in page; GitHub, Bluesky and Slack call their APIs) and records the result in data/profiles/<name>/data/session_status.json. It never logs in, never types a credential, and reports 'busy' instead of waiting when a session is in use. --check-platform runs that same probe for one platform only and leaves every other platform's recorded result alone; --check-platform github checks the profile's GitHub token in the store against GitHub (the login it signs in as, its scopes and what they lack) with no browser at all. --roster additionally reads the profiles roster from the store to show which platforms each profile has a handle for; a store that cannot be reached is the named cause and exit 3, and a roster that reads empty or cannot be read is reported on a Roster: line, not fatal. --chrome additionally reads this machine's Chrome profile mappings from the store, once, and Chrome's own profile list, and adds a Chrome column: the mapped Chrome profile directory and whether the name and account recorded when it was mapped still match (drift, missing, unknown). A mapping is identity, never permission. A Chrome profile list that cannot be read is reported on a Chrome: line, not fatal.
blowhorn profile status [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--check-sessions |
boolean | false |
Probe each configured platform's saved session read-only (in a background browser window unless --headed) and record the result in data/profiles/<name>/data/session_status.json; never logs in, and reports 'busy' instead of waiting for a session another blowhorn process is using |
--check-platform |
string | Run the --check-sessions probe for this one platform only (implies --check-sessions) and leave the other platforms' recorded results as they are. One of: linkedin, x, reddit, slack, bluesky, github; github, bluesky and slack are API calls and open no browser. Unlike --platform it is never read from BLOWHORN_PLATFORM or defaults.platform, so a default cannot narrow a check nobody asked to narrow | |
--roster |
boolean | false |
Also read the profiles roster from the store and report which platforms each profile has a handle for. Needs the store: a store that cannot be reached is the named cause and exit 3; a roster that reads empty or cannot be read is reported on a Roster: line, not fatal |
--chrome |
boolean | false |
Read this machine's Chrome profile mappings from the store and Chrome's profile list, and add a Chrome column: the mapped directory and whether its recorded name and account still match. Opens no browser; a store that cannot be reached is the named cause and exit 3 |
--json |
boolean | false |
Emit machine-readable JSON output |
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Pace of the random delays between 'blowhorn profile status' browser steps: a preset name (fast/normal/slow) or a numeric multiplier (e.g. 0.5, 2.0). Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile status
blowhorn profile status --json
blowhorn profile status --profile kate,rian --check-sessions --headless
blowhorn profile status --profile all --check-sessions --roster --json
blowhorn profile status --profile kate --check-platform github --json
blowhorn profile status --chrome
blowhorn profile status --check-sessions --dry-runOutput: json with --json, text otherwise.
blowhorn profile switch
Set a profile as the default profile in global config.
blowhorn profile switch [OPTIONS] name| Argument | Required | Description |
|---|---|---|
name |
yes | Profile name to set as default |
| Flag | Type | Default | Description |
|---|---|---|---|
--platform |
string | Platform scope for 'blowhorn profile'. One of: bluesky, linkedin, reddit, slack, x, all ('all' means every platform listed here) | |
--pace |
string | Accepted by 'blowhorn profile switch' because --pace is a global flag, but this command does no paced work -- it opens no browser and sleeps between nothing -- so the value changes nothing about how it runs and appears only in the Pace column of the -v summary. Resolved as CLI flag, then BLOWHORN_PACE, then defaults.pace in .blowhorn.yaml (normal when none is set); an unrecognized value is rejected before anything runs |
Also takes the shared flags: --config, --log-dir, --profile, --exclude, --headless, --chrome-launch, --headed, --dry-run, --verbose.
Examples:
blowhorn profile switch james
blowhorn profile switch layer5Output: text.