Reference

Every command, flag, source, and environment variable. For a guided walkthrough, start with GETTING_STARTED.md instead.

Global flags

Every command accepts these.

Flag Default What it does
--data-dir ~/.whodar Directory holding the index and feedback files.   
--policy strict Egress policy: strict, redacted, or open.
--pretty off Indent JSON output.

Sources

Each source is one connector against a single interface; all of them merge into one index with --merge. People join across sources by email, or by an alias file when a source only knows a handle.

Source Reads Credentials Dated
org-csv Org chart CSV: names, titles, teams, topics none no
codeowners CODEOWNERS paths per owner none no
git Commit authors per changed path none yes
slack Users, channels, message history WHODAR_SLACK_TOKEN yes
github Repos, contributors, PRs, issues, CODEOWNERS WHODAR_GITHUB_TOKEN yes
jira Issue assignees and reporters WHODAR_JIRA_* yes
confluence Page creators and editors WHODAR_CONFLUENCE_* yes
pagerduty Services and current on-calls WHODAR_PAGERDUTY_TOKEN no

Dated sources decay: see recency. Undated sources describe the present and keep full weight. Bot accounts (dependabot and friends) are skipped in the git and github sources.

whodar index

Builds or extends the index from one source per run.

whodar index --source SOURCE [scope flags] [--merge]
Flag Default Applies to What it does
--source org-csv all Which source to ingest.
--merge off all Add to the existing index instead of replacing.
--aliases all JSON alias file joining one person across sources.
--half-life-days 180 all Days for a dated record's weight to halve; 0 disables decay.
--changes-file all Write the joiner and leaver diff as JSON.
--embed off all Generate embeddings via Ollama for semantic search.
--embed-model all Ollama embed model (default nomic-embed-text).
--ollama-url localhost all Ollama base URL for --embed.
--file org-csv, codeowners Path to the CSV or CODEOWNERS file (or repo root).
--include-private off slack Ingest private channels if policy allows.
--since-days 180 slack History window in days.
--max-messages 5000 slack Message cap per channel.
--repo github Repo as owner/name, repeatable.
--github-org github Index every repository of an org.
--max-repos 0 = all github Cap repositories taken from --github-org.
--github-emails off github Resolve user emails to join other sources.
--jira-project jira Project key, repeatable.
--jira-jql jira JQL query; overrides --jira-project.
--jira-url jira Site URL; or WHODAR_JIRA_URL.
--max-issues 1000 jira Cap issues read.
--confluence-space confluence Space key, repeatable.
--confluence-cql confluence CQL query; overrides --confluence-space.
--max-pages 2000 confluence Cap pages read.
--repo-path git Local repository root, repeatable.
--git-since-days 365 git History window in days.
--max-commits 2000 git Commit cap per repository.

whodar connect

Sets up a source interactively: it explains the source, shows how to create the credential, reads and validates it, runs the first index, and prints the export line to save. Credentials are validated in memory and never written to disk. connect needs a terminal; scripts use whodar index.

whodar connect [source]
Flag Default What it does
--status off Report which sources are configured, without prompting.

With no argument it shows a menu of every source, marked configured or not. With a source (org-csv, codeowners, git, slack, github, jira, confluence, or pagerduty) it sets up just that one.

whodar vault

Encrypts the on-disk index at rest so a stolen disk or a stray backup cannot read your people graph. Encryption turns on whenever a key is configured, through WHODAR_INDEX_KEY (a base64 32-byte key) or WHODAR_INDEX_PASSPHRASE.

whodar vault keygen     # print a fresh key as an export line
whodar vault status     # report the key and whether the index is encrypted
whodar vault encrypt    # encrypt an existing plain index in place
whodar vault decrypt    # rewrite the index back to plain JSON

With a key set, every whodar index write is encrypted and every read decrypts. Reading an encrypted index without the key fails rather than exposing anything. See PRIVACY.md for the full model.

whodar ask

Answers a question from the index.

whodar ask [flags] QUESTION
Flag Default What it does
--mode keyword Resolver: keyword, semantic, or llm.
--limit 5 Maximum results per section.
--provider ollama LLM provider: ollama, anthropic, openai, or gemini.
--model Chat model for llm mode (defaults per provider).
--embed-model Ollama embed model for semantic and llm modes.
--ollama-url localhost Ollama base URL.
--openai-url OpenAI-compatible base URL including the version path, e.g. http://localhost:1234/v1.
--feedback normal How hard votes move ranking: off, low, normal, high.

Modes: keyword needs no model and always works. semantic matches on meaning using embeddings built with index --embed. llm retrieves candidates, then a model re-ranks them and writes a short recommendation; it cannot invent people. The default provider is a local Ollama server. The anthropic (Claude), openai, and gemini providers are cloud models gated by the egress policy: strict refuses them, --policy redacted sends the question and anonymized numbered candidates (people as title, team, and matched terms; channels as matched terms only) and writes the summary locally, and --policy open sends candidates as-is. The openai provider also speaks to any compatible server via --openai-url; a local one, such as LM Studio, needs no policy opt-in, while a remote one needs --policy open. Each result carries a confidence from zero to one: query coverage scaled by evidence strength, where an explicit topic is proof, a title slightly less, a passing mention half.

whodar feedback

Records, reviews, and clears votes on answers.

whodar feedback record QUESTION (--person ID | --channel NAME) (--helpful | --not-helpful) [--comment TEXT]
whodar feedback list [--query Q | --person ID | --channel NAME]
whodar feedback clear (--query Q | --person ID | --channel NAME | --all)
Flag Applies to What it does
--person all Person identifier from the answer.
--channel all Channel name from the answer.
--query list, clear Match votes for this exact question.
--helpful record The result answered the question.
--not-helpful record The result was wrong for the question.
--comment record Optional note explaining the vote.
--all clear Clear every recorded vote.

By default each net vote multiplies the result's score by 1.25 for that question and its close variants, clamped at three votes either way. Tune it with --feedback off|low|normal|high on ask, serve, and bot: low is a gentle 1.1x capped at two votes, high is 1.5x capped at four, off ignores votes entirely. Votes live in feedback.json under the data directory and survive re-indexing.

whodar serve

Runs the local web UI over the same engine.

whodar serve [--addr HOST:PORT] [--mode keyword|semantic|llm]
Flag Default What it does
--addr 127.0.0.1:8765 Address to listen on.
--mode keyword Default resolver.
--provider ollama LLM provider: ollama, anthropic, openai, or gemini.
--model Ollama chat model for llm mode.
--embed-model Ollama embed model.
--ollama-url localhost Ollama base URL.
--openai-url OpenAI-compatible base URL including the version path.
--feedback normal How hard votes move ranking: off, low, normal, high.

Queries are shareable links: /?q=who+owns+billing runs on load. Every result has feedback buttons.

whodar demo

Explores whodar on a simulated company: all eight sources are built in process and served in the web UI, with no credentials and nothing fetched from the network. Sample data only; it is discarded when the demo stops.

whodar demo

Takes the same flags as serve.

whodar mcp

Serves the index to MCP clients over stdio, so agents such as Claude Code and Claude Desktop can ask who knows what mid-conversation. Tools: whodar_ask, whodar_person, whodar_directory.

whodar mcp [--embed-model name] [--ollama-url url]

Register with claude mcp add whodar -- whodar mcp, or a mcpServers entry in Claude Desktop's config. Semantic mode works when the index was built with --embed and local Ollama is running; keyword needs nothing.

whodar bot

Runs the Slack bot. Mention it, send it a direct message, or use the /whodar slash command; a trailing --llm or --keyword in the text overrides the mode for that answer. Each user gets ten questions a minute, Slack redeliveries are never answered twice, and a dropped connection reconnects with backoff.

whodar bot [--transport socket|events]
Flag Default What it does
--transport socket socket needs no public URL; events serves HTTP.
--addr 127.0.0.1:8766 Address for the events transport.
--mode keyword Default answer mode.
--limit 5 Maximum results per section.
--provider ollama LLM provider: ollama, anthropic, openai, or gemini.
--model Ollama chat model for llm mode.
--embed-model Ollama embed model.
--ollama-url localhost Ollama base URL.
--openai-url OpenAI-compatible base URL including the version path.
--feedback normal How hard votes move ranking: off, low, normal, high.

Environment variables

Credentials are read only from the environment, never from flags, and are never logged or stored.

Variable Used by What it is
WHODAR_SLACK_TOKEN slack source, bot Bot token (xoxb-).
WHODAR_SLACK_APP_TOKEN bot (socket) App-level token (xapp-).
WHODAR_SLACK_SIGNING_SECRET bot (events) Request signature secret.
WHODAR_GITHUB_TOKEN github source Personal access token.
WHODAR_JIRA_URL jira source Site URL, e.g. https://x.atlassian.net.
WHODAR_JIRA_EMAIL jira source Account email for basic auth.
WHODAR_JIRA_TOKEN jira source API token.
WHODAR_CONFLUENCE_URL confluence source Site URL; falls back to WHODAR_JIRA_URL.
WHODAR_CONFLUENCE_EMAIL confluence source Account email; falls back to Jira's.
WHODAR_CONFLUENCE_TOKEN confluence source API token; falls back to Jira's.
WHODAR_PAGERDUTY_TOKEN pagerduty source Read-only API token.
WHODAR_ANTHROPIC_KEY llm anthropic provider Claude API key.
WHODAR_OPENAI_KEY llm openai provider OpenAI-compatible API key.
WHODAR_GEMINI_KEY llm gemini provider Gemini API key.
WHODAR_SERVE_TOKEN serve, demo Bearer token; required to bind beyond localhost.
WHODAR_POLICY_FILE all commands Extra policy file; a locked /etc/whodar/policy.json overrides it.
WHODAR_INDEX_KEY index encryption Base64 32-byte key that enables at-rest encryption.
WHODAR_INDEX_PASSPHRASE index encryption Passphrase for at-rest encryption; prompted if unset on a terminal.

Identity aliases

Handles that clearly belong to one person join automatically: a handle-only identifier such as codeowners:carol-lee or github:carollee merges with the one person whose name or email local-part flattens to the same string, so Carol Lee, carol-lee, and [email protected] stay one entry. A handle matching nobody, or matching more than one person, stays separate.

An alias file joins the rest, when neither email nor name can. The file maps a canonical identifier to its aliases:

{"[email protected]": ["github:angela-malone", "codeowners:angela-malone"]}

Pass it once with index --aliases; the mapping persists in the index and joins entries indexed before the file existed. Joined identifiers appear in answers under identities. See examples/aliases.json.

Ranking

Keyword scores weight rarer query terms higher, then cap and saturate each term's accumulated weight, so repeating a word in chat all day cannot outrank the person with the explicit topic, title, or ownership signal. People with far more indexed text than average are further discounted for verbosity. Recency decay and feedback votes then scale the result.

A term that matches nothing falls back to fuzzy matching: the closest indexed term within one edit (four-letter terms and up) or two edits (seven and up) scores instead, at a penalty per edit so an exact match always outranks a corrected one. Corrected terms say so in the reasons, e.g. terrafrom (topic, fuzzy).

Recency

Dated records lose half their weight per half-life, 180 days by default, so today's owner outranks one from years ago. Tune with --half-life-days at index time; 0 disables decay. Undated sources (org chart, CODEOWNERS, on-call) describe the present and never decay.

Policy

The egress policy decides what whodar may send to a model. strict (default) permits nothing beyond a local model server; non-local --ollama-url and --openai-url values and the cloud providers count as egress and are refused. redacted permits only the known provider hosts (api.anthropic.com, api.openai.com, generativelanguage.googleapis.com) and strips identifiers: the question goes out as typed, people leave as numbered roles (title, team, matched terms), channels leave as numbered matched terms with no names or topics, the model returns numbers, and the summary is written locally. open sends full candidate detail to any host. The policy does not gate indexing, which talks only to the sources you name with your tokens when you run whodar index, or the bot posting answers back to your Slack workspace.

An organization can pin the policy with a locked file. A locked /etc/whodar/policy.json always wins: WHODAR_POLICY_FILE and --policy are then ignored. The lock constrains the installed binary for regular users; it is not a security boundary against an administrator. Private-channel ingest can be denied the same way. See examples/policy.json.

Files

Everything lives under --data-dir (default ~/.whodar):

File What it holds
index.json The graph, postings, embeddings, and identity aliases.
feedback.json User votes, kept apart so they survive re-indexing.