Skip to main content
A profile is a named runtime context for Task Manager: its own data directory, auth storage, HTTP port, and (for client profiles) its own remote api_url and api_key. Profiles give you machine-local isolation without mixing data, sessions, or credentials between setups.

Where profiles live

A small default-profile pointer lives one level up, alongside the profiles directory:

Profile roles

Every profile has a role, set by the wizard mode you choose: You never set role by hand — the setup mode picks it. To convert a profile from one role to the other, delete it and re-run the appropriate wizard.

Configuration schema

Field matrix

Auth directory is fixed. The web passphrase hash and CLI API key hashes always live at <profileRoot>/auth/ (i.e. ~/.taskmanager/profiles/<name>/auth/). There is no auth_dir field — the wizard does not prompt for it, and adding one to config.json by hand has no effect.

Validation rules (enforced when the config is loaded)

  1. role must be "server" or "client".
  2. Server profile: port and data_dir are required; api_url must not be present (it is auto-derived from port).
  3. Client profile: api_url (absolute URL) and api_key are required; port, data_dir, open_browser, bind_address, require_cli_api_key must not be present.
  4. Public exposure requires a key. If bind_address is non-loopback (anything other than 127.0.0.1, localhost, ::1), require_cli_api_key: false is rejected.
  5. Bootstrap warning (not an error): if require_cli_api_key === true on a server profile and no api_key is set, the loader warns that the local CLI will fail with auth_cli_key_required until you set one (or pass --api-key per command). External callers may still authenticate via cli-api-keys.json.
Validation failures throw CliError(invalid_config) (exit code 9). The error names the offending field and the profile path.

Example — same-machine server profile (no key)

Example — hardened single-host (loopback + forced key)

Example — public bind on the LAN (advanced, hand-edited)

See Advanced: exposing the API on a network interface for when to use this and what to set together.

Example — client profile (talks to a remote server)

Default-profile pointer

~/.taskmanager/config.json:
Both --setup-server and --setup-client offer to write this pointer at the end of the wizard. Change it later with:
profile use errors if <name> doesn’t exist on disk.

How the CLI picks a profile

Resolution order, per command:
  1. --profile <name> on the command line (highest priority).
  2. default_profile in ~/.taskmanager/config.json.
  3. If neither is set and exactly one profile exists on disk, use it implicitly.
  4. Otherwise the CLI errors with the list of available profiles and a hint to run hirotaskmanager profile use <name> (or pass --profile).

How a profile is created

Use the wizards in hirotaskmanager. Each one writes the profile’s config.json, optionally mints a CLI API key, and optionally sets the default-profile pointer. Plain hirotaskmanager with no configured profile asks “server or client?” once, then routes to the right flow. To re-run setup for an existing profile (change port, paths, etc.), use:
Re-running pre-fills your existing answers and refuses role changes — delete the profile and re-setup to convert.

Updating a profile

  • Interactive: hirotaskmanager --setup --profile <name>.
  • Manual: edit ~/.taskmanager/profiles/<name>/config.json carefully (keep valid JSON). Back up the file first. Validation errors will surface on the next CLI invocation.

Advanced: exposing the API on a network interface

bind_address is treated as an advanced, config-file-only setting. The setup wizard never asks for it: new profiles always default to 127.0.0.1 (loopback), and re-running the wizard preserves whatever value is already in config.json. When loopback is the right answer:
  • Same machine. The CLI on this machine talks to http://127.0.0.1:<port> automatically.
  • Remote access via reverse proxy. Put Caddy, nginx, or similar in front of the loopback API and terminate TLS there. The API stays unreachable from the network directly.
When you want the API socket itself reachable from the network (LAN, Tailscale, etc.), edit config.json by hand and set both fields together:
The validator enforces this pairing: any non-loopback bind_address (anything other than 127.0.0.1, localhost, ::1) must also have require_cli_api_key: true, set explicitly. Setting bind_address to 0.0.0.0 without require_cli_api_key, or with require_cli_api_key: false, is rejected with invalid_config (exit code 9) on the next CLI invocation. Mint a CLI API key for any caller that will reach the public socket:
Plain HTTP on a non-loopback host sends traffic in cleartext; prefer a reverse proxy with TLS for any access beyond a trusted local network.

Hiro developers only

For Hiro developers working on Task Manager itself, --dev and --profile are independent:
  • --dev changes runtime behavior, including the default port (3002) and dev CORS.
  • --profile selects the profile directory for config, auth, and data.
  • The dev profile is not magic. It is just a profile name.
  • All profiles, including dev, store data under ~/.taskmanager/profiles/<name>/data/ unless you override the path.
See Advanced setup → For developers for a worked dual-profile example.