crow-central-agency
v0.25.6
Published
Multi-instance Claude Code manager with a bundled web UI for orchestrating multiple Claude Code agents from one place.
Downloads
917
Maintainers
Readme
Crow Central Agency
Multi-instance Claude Code manager with a bundled web UI for orchestrating multiple Claude Code agents from one place.
Use it to build research crews, monitoring watchdogs, content pipelines, support triagers, or anything else you can shape from agents coordinating with each other.
Features
- Multi-agent dashboard - run many Claude Code agents in parallel, each with its own workspace, model, persona, and tool set.
- Agent coordination - compose agents into layered relationships that produce and share artifacts, adaptable to a wide range of workflows and scenarios.
- Flexible triggers - ad-hoc chat, assigned tasks, reminders, or scheduled prompts on configurable day-of-week / time-of-day windows.
- Rich configuration - per-agent MCP servers, permission modes, Discord bots, RSS feeds (with optional LLM summarization), and AI-assisted persona /
AGENT.mdgeneration. - Connectors - per-agent identities for external services that the framework consumes to power built-in tool families. Each agent connects independently, so two agents can call the same provider (e.g. Gmail) under different accounts.
- OpenTelemetry export - optional traces and metrics for every agent query (see below).
Requirements
- Node.js
>=24 - Claude Code CLI available on
PATH(or setCLAUDE_CLI_PATH)
Quick start
Install Node.js
>=24. Check your version withnode --version. If it is missing or older, install from nodejs.org or use nvm (nvm install 24 && nvm use 24).Install the Claude Code CLI. Make sure the
claudecommand is on yourPATH(or pointCLAUDE_CLI_PATHat the binary). Verify withclaude --version.Create a
.envfile with anACCESS_KEY. Pick any non-empty string — a long random value is recommended. A dedicated folder like~/.crowkeeps it out of your project directories:mkdir -p ~/.crow echo "ACCESS_KEY=your-secret-value" > ~/.crow/.envTIP: Generate a strong value with
openssl rand -hex 32.Start Crow, pointing at the env file you just created:
npx crow-central-agency --env-file ~/.crow/.envOpen http://localhost:3101 in your browser. On first load the UI prompts for the access key — paste the same value you set in step 3.
Run from a cloned repo
git clone https://github.com/hmmroger/crow-central-agency.git
cd crow-central-agency
npm install
npm run build
npm start -- --env-file ~/.crow/.envnpm start runs the same single-box entry point as the published CLI.
Configuration
Crow reads configuration from environment variables. The simplest approach is to copy .env.example to .env in the directory you launch from — dotenv loads it automatically on startup.
cp .env.example .envRequired: ACCESS_KEY
ACCESS_KEY is the only required variable. It is a shared secret between the server and the browser UI — you choose the value yourself; there is no default and no external provisioning.
- Pick any non-empty string (a long random value is recommended, e.g.
openssl rand -hex 32). - Set
ACCESS_KEY=<your value>in.env. - On first load, the web UI prompts for the access key — enter the same value. It is then stored in the browser and sent as
Authorization: Bearer <key>on API requests (and as a query param on the WebSocket connection).
Requests without a valid key receive 401 Unauthorized.
Custom env file path
To load a .env from a non-default location, pass --env-file:
npx crow-central-agency --env-file /path/to/custom.envThe same flag works with npm start when running from a clone:
npm start -- --env-file /path/to/custom.envIf --env-file is omitted, dotenv falls back to .env in the current working directory.
Other variables
See .env.example for the full list, including:
HOST/PORT— server bind address (defaults:localhost:3101). KeepHOST=localhostand front the server with a secure tunnel for remote access rather than binding to0.0.0.0.CORS_ORIGINS— only needed when the frontend is served from a different origin (e.g. during frontend dev). Single-box deployments can leave it unset.LOG_LEVEL— log verbosity (defaults todebugin development,infootherwise).CROW_SYSTEM_PATH— directory for Crow's file-based storage. Defaults to~/.crow.CROW_SYSTEM_AGENT_NAME— display name for the built-in Crow system agent (default:Crow).STATIC_PATH— override the directory served as frontend assets (auto-detected from the published bundle).CLAUDE_CLI_PATH— explicit path to the Claude Code CLI binary when it is not onPATH.CLOSED_TASK_RETENTION_DAYS— how long to keep closed tasks before pruning on startup (default:30).FEED_ITEM_RETENTION_DAYS/FEED_REFRESH_IN_MINUTES— feed item retention window and refresh cadence.TEXT_GENERATION_*— optional OpenAI-compatible endpoint that enables the AI-assisted persona /AGENT.mdgeneration features in the agent editor.FEED_TEXT_GENERATION_*— optional OpenAI-compatible endpoint used by the feed manager to summarize feed items into a consistent length for better agent consumption.AUDIO_GENERATION_*— optional Gemini TTS configuration that powers the play-message button on the agent console. See Audio generation below.GOOGLE_CONNECTOR_CLIENT_ID/GOOGLE_CONNECTOR_CLIENT_SECRET/CONNECTOR_CALLBACK_URL— OAuth credentials for the Google connector. Required if you want agents to access Gmail / Calendar / Contacts. See Connectors below.OAUTH_PENDING_STATE_TTL_MS— how long an unfinished OAuth flow stays valid before being swept (default:600_000, i.e. 10 minutes).OTEL_*— optional OpenTelemetry export.
Audio generation
Crow can synthesize agent text messages to speech and play them back in the agent console (per-message play button) or dashboard.
Configuration
The feature is opt-in — the play button only works when all three audio
env vars are set. Add to .env:
AUDIO_GENERATION_PROVIDER=GOOGLE
AUDIO_GENERATION_API_KEY=<your Google API key>
AUDIO_GENERATION_MODEL=gemini-2.5-flash-preview-ttsPer-agent overrides (voice name + style prompt) live in the Voice Config section of the agent editor. When the agent's voice is changed after audio was already generated, the next play regenerates with the new voice.
Google API key requirements
The AUDIO_GENERATION_API_KEY must be a Google API key with access to the
Gemini API.
You can use the same key as TEXT_GENERATION_API_KEY if that is also a
Gemini-backed configuration, but the two are read independently.
Connectors
Connectors are a framework-level capability - they are not tools agents call directly. A connector binds a per-agent identity to an external service; the framework then uses that identity to power built-in features for the agent. Today the Google connector backs the Gmail tool family: when an agent has a Google connection, the Gmail MCP server is wired up automatically.
Because the binding is per-agent, two agents can connect to the same provider as different identities. An inbox-triage agent can use one Google account while a calendar-scheduling agent uses another, and neither sees the other's credentials.
Google connector
Status: Gmail tool family is live (list / read / thread / send / reply / trash, plus full label management - see below). Calendar and Contacts scopes are granted at sign-in time so agents can reuse the same connection once their tool families ship.
Tools shipped today (Gmail):
list_gmail_messages,get_gmail_message_content,get_gmail_thread— read inbox, message bodies (rendered as markdown), and conversation threads.send_gmail_message,reply_to_gmail_message— compose and reply.move_gmail_message_to_trash— soft-delete a message.list_gmail_labels— discover system + user-defined labels.update_gmail_message_user_labels- attach / detach user labels on a message.update_gmail_message_state— flip read / archived / starred / important flag on a message.create_gmail_user_label,delete_gmail_user_label— manage user-defined labels (folders/tags).
Setup (Google)
The Google connector authenticates via OAuth, which means you create a small "OAuth app" in your own Google Cloud account and give Crow its credentials.
This is a one-time setup. The single OAuth app you create here works
for any number of Google accounts (up to 100 for unverified app). Each agent in
Crow signs in independently, so one agent can connect as [email protected],
another as [email protected], and a third can share
agent1's account. The only per-account step you'll repeat is adding each new Google account
as a test user on your OAuth app's Audience page (covered in
step 4 below; revisit later when you want to add a new account).
If you have never used Google Cloud before, follow every step; experienced users can skim.
1. Sign in to Google Cloud Console.
Go to console.cloud.google.com and sign in with your Google account you want to manage the OAuth app (the OAuth app and the user you connect with don't have to match). If this is your first time, accept the terms of service. No billing is required for creating OAuth app.
Note: Start free button would start a free trial and will require credit card information.
2. Create a project.
Click the project picker in the top bar (next to "Google Cloud") and choose
New Project. Give it any name (e.g. Crow Connector) and click Create. After
a few seconds, switch to the new project from the same picker.
3. Enable the APIs the connector needs.
Open APIs & Services → Library from the left sidebar (or the hamburger menu). Search for and enable each of:
- Gmail API
- Google Calendar API
- Google People API
Click each result, then click the Enable button.
4. Configure the OAuth consent screen and add test users.
Open APIs & Services → OAuth consent screen. Pick External (unless you have a Google Workspace organization). Fill in the required fields:
- App name — anything, e.g.
Crow Connector. - User support email - your email.
- Developer contact email - your email.
Save and complete the wizard (no changes needed on the Scopes / Optional Info pages).
Then go to the Audience tab (left sidebar of the OAuth consent screen section). Under Test users, click Add users and add every Google account you intend to connect from Crow - your own account, plus any other accounts you'll use for separate agents. Save.
While the app is in Testing mode, only the accounts on the Audience page can sign in - that is the expected setup for personal use. You don't need to publish or get verified by Google.
Adding more accounts later: every time you want a new agent to connect with a Google account that isn't already a test user, come back to this Audience page and add it. The OAuth app, your
.env, and existing connected agents are unaffected.
5. Create the OAuth client credentials.
Open APIs & Services → Credentials → Create Credentials → OAuth client ID.
Application type: Web application (this is correct even though Crow runs locally - the OAuth flow uses an HTTP redirect).
Name: anything, e.g.
Crow local.Authorized redirect URIs: click Add URI and paste exactly:
http://localhost:3101/auth/callback(If you changed
PORTin your.env, use that port instead.)
[!NOTE] You can register multiple callback URIs. This is useful if you also run Crow behind a local TLS-terminating reverse proxy (e.g. Caddy or nginx with a self-signed cert) so the OAuth callback comes in over HTTPS - for example, add
https://localhost:8080/auth/callbackalongside the plainhttp://localhost:3101/auth/callback. SetCONNECTOR_CALLBACK_URLto whichever URL the browser will actually hit (typically the proxy's), and add the proxy's origin toCORS_ORIGINS.Google rejects raw LAN IPs (e.g.
192.168.1.10) as redirect URIs. To reach Crow from another device on your network, map a hostname likecrow.lanto the host's IP via yourhostsfile (or your router's local DNS), and registerhttps://crow.lan/auth/callbackinstead.
Click Create. A popup shows the Client ID and Client secret - keep this open or copy both values somewhere temporary; you'll need them in the next step.
6. Add the credentials to your .env.
GOOGLE_CONNECTOR_CLIENT_ID=<paste the Client ID>
GOOGLE_CONNECTOR_CLIENT_SECRET=<paste the Client secret>
CONNECTOR_CALLBACK_URL=http://localhost:3101/auth/callbackThe redirect URI here must match the one you entered in step 5 character for character.
7. Restart Crow and connect an agent.
Restart the server so it picks up the new env vars. Then in the UI:
- Open the agent you want to give Gmail access (or create one).
- Scroll to the Connectors section in the editor.
- Click Connect next to Google.
- Sign in as one of the test users you added in step 4 and approve the requested scopes.
- The connector row switches to "Connected as
<your-email>" — the Google connection is now stored for this agent. - Scroll to the MCP Servers section of the same editor. The Gmail server now appears in the list. Toggle it on, then save the agent. Until you enable it here, the connection is stored but the agent has no Gmail tools wired in.
[!NOTE] On the first sign-in for a Google account, the consent screen lists each requested scope with its own checkbox (Gmail, Calendar, Contacts, etc.). Google leaves them unchecked by default. Tick all of them before clicking Allow — any scope you skip won't be granted, the corresponding tool family won't work for this agent, and the connector row will show a "reconnect to enable new features" hint until you redo the flow with the missing scopes selected.
Repeat step 7 for each additional agent that needs Google access — same OAuth app, any Google account that's on your Audience test-users list.
Disconnecting
In the agent editor, the Disconnect button on the connector row clears
both the keyring entry and the on-disk metadata for that agent. Revoking
from the Google account permissions page
is also detected on the next refresh - Crow surfaces it as UNAUTHORIZED
and clears the connection automatically.
OpenTelemetry
Crow emits traces and metrics via @opentelemetry/sdk-node. Telemetry is off by default — set OTEL_ENABLED=true along with the standard OTel env vars (OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, etc.) to export to your collector.
Built-in HTTP/Fastify/Undici instrumentations cover inbound requests and outgoing HTTP calls. On top of that, Crow adds agent-query instrumentation under the crow.agent tracer and meter.
[!NOTE] Unlike typical operational telemetry, Crow's spans include user-authored content on attributes and events — notably
agent.nameandtool.description(the latter often derived from tool-use input). Error messages and recorded exceptions (agent.error) may also contain PII surfaced from underlying tools or model output. Anything you export is visible to whatever OTel backend you point at, so only send telemetry to a provider you trust.
Traces — crow.agent
One span per agent query, named agent.query.
Span attributes:
agent.id,agent.name— identity of the agent being queriedagent.source_type— what triggered the query (e.g.USER,TASK,LOOP)agent.session_id— Claude Code session id (set once theINITevent arrives)agent.done_type— terminal reason (aborted, or the done-event type on success)agent.duration_ms— total query durationagent.error— error message on failure (span status set toERROR, exception recorded with stack trace)
Span events:
tool_use— emitted per tool invocation withtool.nameandtool.descriptionmessage_done— emitted per assistant message withmessage.input_tokens,message.output_tokens,message.total_input_tokens(the last includes cache-read and cache-creation tokens)
Metrics — crow.agent
All metrics are tagged with agent.id and agent.name.
agent.query.input_tokens(histogram, unittokens) — total input tokens per assistant message, including cache-read and cache-creation tokensagent.query.output_tokens(histogram, unittokens) — output tokens per assistant messageagent.query.duration(histogram, units) — total duration of each agent queryagent.query.tool_use(counter, unitinvocations) — tool invocations, additionally tagged withtool.name
License
MIT
