From agentchannels
Initializes agentchannels stack conversationally: validates Anthropic API key, selects/configures Claude agent and environment, optional vaults, Slack bot credentials; writes to .env after all phases succeed.
npx claudepluginhub agentchannels/agentchannels --plugin agentchannelsThis skill uses the workspace's default tool permissions.
Initialize a complete agentchannels stack — Claude Managed Agent, Environment, optional Vault IDs, and Slack bot — by collecting credentials conversationally and writing them to `.env`.
Starts agentchannels bridge server connecting Slack to Claude Managed Agents via Socket Mode. Verifies .env credentials like CLAUDE_AGENT_ID, ANTHROPIC_API_KEY, and Slack tokens before launch.
Interact with Slack workspaces via CLI using bot tokens: send messages, list/read channels, manage reactions, and handle multi-bot auth. For CI/CD and server-side bots.
Automates ClaudeClaw setup: installs dependencies, authenticates messaging channels, registers main channel, starts background services. Triggers on setup, install, configure claudeclaw, or first-time requests.
Share bugs, ideas, or general feedback.
Initialize a complete agentchannels stack — Claude Managed Agent, Environment, optional Vault IDs, and Slack bot — by collecting credentials conversationally and writing them to .env.
This skill guides the user through the full agentchannels setup in five phases:
ANTHROPIC_API_KEY against the Anthropic APIAll five phases complete before anything is written to .env. If any phase fails, the user stays in that phase until it succeeds or they abort.
Why this order? Agent and environment validation require a live API key. Validating these before Slack setup means users never configure Slack only to discover their agent is broken — the failure is surfaced immediately.
.envBefore asking any questions, use the Read tool to check for an existing .env file in the current working directory. Extract these values if present:
ANTHROPIC_API_KEYCLAUDE_AGENT_IDCLAUDE_ENVIRONMENT_IDCLAUDE_VAULT_IDSSLACK_BOT_TOKEN, SLACK_APP_TOKEN, SLACK_SIGNING_SECRET, SLACK_REFRESH_TOKENStore them as defaults for the steps that follow. Never echo raw token or key values back to the user — show only the prefix (e.g., sk-ant-... confirmed) or confirm the last four characters.
If ANTHROPIC_API_KEY is already set in .env or the current environment, inform the user and validate it immediately (see 1b):
"I found an existing
ANTHROPIC_API_KEY(ending...{last4}) in.env. Validating it now..."
If no key is found:
"To get started, I need your Anthropic API key. You can find it at https://console.anthropic.com/keys (starts with
sk-ant-).Please paste it when prompted — it will not be displayed."
Collect it without echoing (treat like a password field).
Run the following Bash command to validate the key by listing agents as a lightweight health check:
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
await client.beta.agents.list({ limit: 1 });
console.log('VALID');
} catch (e) {
console.log('INVALID:' + e.message);
}
EOF
VALID: proceed to Phase 2.INVALID:: show the error message and re-prompt for the key. Do not proceed until the key validates successfully.If CLAUDE_AGENT_ID is found in .env, validate it immediately:
"Found
CLAUDE_AGENT_ID=<id>in.env. Validating it..."
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const agent = await client.beta.agents.retrieve('<agent_id>');
console.log(JSON.stringify({ id: agent.id, name: agent.name }));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
Valid response: Confirm (✅ Agent "<name>" (<id>) is accessible) and ask whether to keep it or choose a different one.
Error / not found: Warn the user explicitly — do not silently drop the stale value:
⚠️ The agent ID in your
.env(<id>) is no longer accessible (stale). You'll need to select or create a replacement.
Then continue to 2b.
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const response = await client.beta.agents.list({ limit: 20 });
const data = response.data ?? response;
console.log(JSON.stringify(Array.isArray(data)
? data.map(a => ({ id: a.id, name: a.name }))
: []));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
If the list is empty or returns an error, skip selection and jump directly to 2c (create). Do not show a blank menu.
If agents exist, present them with a final "Create a new agent" option:
"Here are your existing Claude Managed Agents:
<name>(<id>)<name>(<id>) ... N. Create a new agentWhich would you like to use?"
Ask:
agentchannels-botclaude-opus-4-5)Then create:
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const params = { name: '<name>' };
if ('<model>') params.model = '<model>';
if ('<description>') params.description = '<description>';
if ('<system>') params.system = '<system>';
const agent = await client.beta.agents.create(params);
console.log(JSON.stringify({ id: agent.id, name: agent.name }));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
✅ Agent "<name>" created — ID: <id>) and proceed to Phase 3.Agents and environments are independent top-level resources. The environment does not need to share a name with the agent, though a matching suffix (e.g., agentchannels-bot-env) is a helpful convention.
If CLAUDE_ENVIRONMENT_ID is found in .env, validate it:
"Found
CLAUDE_ENVIRONMENT_ID=<id>in.env. Validating it..."
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const env = await client.beta.environments.retrieve('<env_id>');
console.log(JSON.stringify({ id: env.id, name: env.name }));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
ANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const response = await client.beta.environments.list({ limit: 20 });
const data = response.data ?? response;
console.log(JSON.stringify(Array.isArray(data)
? data.map(e => ({ id: e.id, name: e.name }))
: []));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
If the list is empty, skip to 3c (create). If environments exist, present them with a "Create a new environment" option.
Ask:
<agent-name>-envANTHROPIC_API_KEY='<key>' node --input-type=module <<'EOF'
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
try {
const params = { name: '<name>' };
if ('<description>') params.description = '<description>';
const env = await client.beta.environments.create(params);
console.log(JSON.stringify({ id: env.id, name: env.name }));
} catch (e) {
console.log('ERROR:' + e.message);
}
EOF
✅ Environment "<name>" created — ID: <id>) and proceed to Phase 4."Do you have any Vault IDs for MCP tool OAuth credentials? Vaults let the agent access services like Google Drive or GitHub using stored OAuth tokens managed by Anthropic.
Enter vault IDs as a comma-separated list (e.g.,
vault_abc123,vault_def456), or press Enter to skip."
CLAUDE_VAULT_IDS is already in .env, show the existing value as the default and offer to keep or replace it.CLAUDE_VAULT_IDS is left unset (omitted from .env).Note: Vault creation is out of scope for this wizard. To create a vault, visit the Anthropic Console.
"How would you like to set up your Slack integration?
- Manual — I already have a Slack Bot Token (
xoxb-...), App-Level Token (xapp-...), and Signing Secret- Automatic — I have a Slack Refresh Token (
xoxe-...) and want the CLI to create the app for meWhich path would you like to use?"
Ask for each credential separately and validate the format before proceeding:
Slack Bot Token — must start with xoxb- and be at least 20 characters. Found at: Basic Information → OAuth & Permissions → Bot User OAuth Token on api.slack.com/apps.
Slack App-Level Token — must start with xapp- and be at least 20 characters. Found at: Basic Information → App-Level Tokens → Generate Token and Scopes (add scope connections:write). This token enables Socket Mode (no public URL needed).
Slack Signing Secret — any non-empty string at least 10 characters. Found at: Basic Information → App Credentials → Signing Secret.
Tell the user: "Please paste credentials one at a time. Do not include multiple tokens in a single message."
Ask in order:
Slack app name — display name for the app (default: "General Agent"). Confirm before proceeding — renaming later requires visiting api.slack.com/apps.
Slack app description (optional) — one-line description shown in the workspace app directory.
Slack Refresh Token — must start with xoxe- and be at least 20 characters.
.env automatically."Once all phases are complete, call ach init slack --non-interactive with all collected credentials as inline environment variables. Never pass credentials as CLI flags — inline env vars keep them out of process listings.
ANTHROPIC_API_KEY='<api_key>' \
CLAUDE_AGENT_ID='<agent_id>' \
CLAUDE_ENVIRONMENT_ID='<env_id>' \
SLACK_BOT_TOKEN='<bot_token>' \
SLACK_APP_TOKEN='<app_token>' \
SLACK_SIGNING_SECRET='<signing_secret>' \
ach init slack --non-interactive
With optional vault IDs:
ANTHROPIC_API_KEY='<api_key>' \
CLAUDE_AGENT_ID='<agent_id>' \
CLAUDE_ENVIRONMENT_ID='<env_id>' \
CLAUDE_VAULT_IDS='<vault_ids>' \
SLACK_BOT_TOKEN='<bot_token>' \
SLACK_APP_TOKEN='<app_token>' \
SLACK_SIGNING_SECRET='<signing_secret>' \
ach init slack --non-interactive
ANTHROPIC_API_KEY='<api_key>' \
CLAUDE_AGENT_ID='<agent_id>' \
CLAUDE_ENVIRONMENT_ID='<env_id>' \
SLACK_REFRESH_TOKEN='<refresh_token>' \
ach init slack --non-interactive \
--app-name '<app_name>' \
--app-description '<app_description>'
With optional vault IDs:
ANTHROPIC_API_KEY='<api_key>' \
CLAUDE_AGENT_ID='<agent_id>' \
CLAUDE_ENVIRONMENT_ID='<env_id>' \
CLAUDE_VAULT_IDS='<vault_ids>' \
SLACK_REFRESH_TOKEN='<refresh_token>' \
ach init slack --non-interactive \
--app-name '<app_name>' \
--app-description '<app_description>'
Omit --app-description if the user didn't provide one. If no name was supplied, omit --app-name too — the CLI defaults to "General Agent".
If
achis not found in PATH: trynpx agentchannels init slack --non-interactiveor./node_modules/.bin/ach init slack --non-interactiveas fallbacks.
Confirm that all credentials were saved to .env:
✅ Setup complete! The following were written to
.env:
ANTHROPIC_API_KEY— Anthropic API key confirmedCLAUDE_AGENT_ID— Agent:<name>(<id>)CLAUDE_ENVIRONMENT_ID— Environment:<name>(<id>)CLAUDE_VAULT_IDS—<vault_ids>(if provided)SLACK_BOT_TOKEN,SLACK_APP_TOKEN,SLACK_SIGNING_SECRET— Slack credentialsNext step: Run
/ach:serveto start the bridge, orach deploy railwayto deploy to Railway.
Show the error output and diagnose:
| Error pattern | Remediation |
|---|---|
| Token format error | Re-prompt for the specific credential that failed (return to Phase 5) |
ANTHROPIC_API_KEY invalid | Re-run Phase 1 |
| Agent / environment not found | Re-run Phase 2 or Phase 3 to select a valid ID |
| OAuth timeout (automatic path) | Explain the browser window must be completed within 5 minutes; offer to retry Phase 5 |
| Insufficient credentials | Clarify which tokens are missing and re-prompt |
.env: The CLI automatically backs up the existing .env before writing. Inform the user their previous credentials are preserved in .env.bak..env: If an existing CLAUDE_AGENT_ID or CLAUDE_ENVIRONMENT_ID is no longer accessible via the API, warn the user explicitly. Never silently overwrite or discard the stale ID without informing the user.xoxb-... confirmed, sk-ant-... ending Xk3Q).connections:write scope exists.ach init slack run directly in a terminal (without --non-interactive). If a user wants that experience, instruct them to run ach init slack in their terminal instead.