Skip to content
Back to skills

Community

BSecurity

This skill should be used when managing community presence across platforms (Discord, GitHub, X/Twitter, Bluesky, LinkedIn, Hacker News). It provides sub-commands for generating digests, checking health metrics, and listing enabled platforms.

  • 16 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
data-aigoshellbashgitapi

Works with

  • claude code
  • cursor
  • cli
  • api

Security analysis

B75/100
  • criticalSends environment variables or credentials to an external URL

Pro scans all 12 files and shows the line behind each finding

Scanned October 7, 2026

npx -y skills add jikig-ai/soleur --skill community --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Community?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Community
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/jikig-ai-community/badge)](https://www.skillsdirectory.com/skills/jikig-ai-community)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: community
description: "This skill should be used when managing community presence across platforms (Discord, GitHub, X/Twitter, Bluesky, LinkedIn, Hacker News). It provides sub-commands for generating digests, checking health metrics, and listing enabled platforms."
---

<!-- soleur-cloud-mode:start -->
**Cloud Mode (Devin):** before pipeline work run `bash "${CLAUDE_PLUGIN_ROOT}/scripts/cloud-detect.sh"`. If `CLAUDE_PLUGIN_ROOT` is unset (cloud exec shells do not export it), resolve the root by IDENTITY, never by script basename: for `d` in `"$HOME/.local/share/devin/cli/plugins/cache"` and `/opt/.devin/plugins`, skip unless `[ -d "$d" ]`, then `MANIFEST="$(find "$d" -path '*/.claude-plugin/plugin.json' -exec grep -l '"name"[[:space:]]*:[[:space:]]*"soleur"' {} + 2>/dev/null | head -1)"`, `ROOT="${MANIFEST%/.claude-plugin/plugin.json}"` — one resolution, two consumers: `$ROOT/scripts/cloud-detect.sh` and `$ROOT/scripts/precommit-guard.sh`. (Shape check, not authentication: a planted `{"name":"soleur"}` dir passes — ADR-179 A11.) `local` or `not-local:no-devin-env` proceeds normally; any other `not-local:<reason>` applies `<plugin-root>/devin/INSTRUCTIONS.md` §Cloud Mode: emit the `--banner`, fan out sequentially with `Reviewed-Coverage: sequential-fallback` disclosure (never claim an independent review ran), `message_user` ack before any secrets read or production mutation, and run `precommit-guard.sh` before any `git commit` — hooks do not fire in cloud.
<!-- soleur-cloud-mode:end -->

<!-- grok-harness-invoke:start -->
**Grok Build (`plugins/soleur/lib/harness.ts` `invokeSkill()`):** Read this SKILL.md in this process and run it to completion. A one-segment `soleur:<name>` in this document names a SKILL — on Grok Build, Read `plugins/soleur/skills/<name>/SKILL.md` in this process; it is not a nested tool_use. A multi-segment id such as `soleur:<domain>:<name>` names an AGENT: spawn it, never Read it, and on Grok Build spawn_subagent takes the id with its colons replaced by hyphens (`agentIdToGrokSubagentType`). **Claude Code:** Skill tool for a skill (`soleur:<name>`), Task tool with `subagent_type` for an agent. Forbidden is executing a subset, not the Read.
<!-- grok-harness-invoke:end -->

# Community Management

Manage community presence across Discord, GitHub, X/Twitter, Bluesky, LinkedIn, and Hacker News. Detects enabled platforms from environment variables (or always-on for GitHub and HN) and delegates data collection to platform-specific scripts.

<!-- operator-typed-render:start -->
**Any message this skill PRINTS that tells the operator to run a skill or command renders at emit time.** The doc names it canonically (`soleur:<name>`, ADR-226); before printing, render it as the active harness's **operator-typed form** per `formatSkillInvocation` (`plugins/soleur/lib/harness.ts`), which owns the per-harness slash and sigil forms — the operator types that string into a fresh session where no routing contract is in context, so a bare canonical name is model-discretion there rather than a dispatch. This covers abort messages, `AskUserQuestion` prompts and options, `Display`/`echo` lines and resume prompts alike; an agent-read instruction stays canonical.
<!-- operator-typed-render:end -->

## Arguments

`$ARGUMENTS` is parsed for a sub-command and optional flags:

```text
community [sub-command] [--headless] [--platform PLATFORM]
community engage [--max-results N] [--headless]
```

If `$ARGUMENTS` is empty or unrecognized, present the sub-command menu below.

If `--headless` is present, skip all interactive prompts and approval gates.

## Platform Detection

Platform detection is centralized in [community-router.sh](./scripts/community-router.sh). Run at the start of every sub-command:

```bash
bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/community-router.sh" platforms
```

The anchor is **bare and quoted** (ADR-179 decision 1), not a `:-` default arm on the token
and not a bare `plugins/soleur/…` path. The router dispatches to the scripts that consume
`DISCORD_BOT_TOKEN`, `X_API_SECRET` and `LINKEDIN_ACCESS_TOKEN`, so a CWD-relative resolution would
hand those credentials to whatever `skills/community/scripts/community-router.sh` exists in the tree
the session happens to sit in.

The same applies to the four `*-setup.sh` invocations under `platforms` below — those were
**bare repo-relative** until #7450 review, which is strictly worse than the `:-` form removed here,
since a bare path is CWD-relative unconditionally. All five are pinned by `redact-sentinel.test.sh`
Test 24, which discovers credential-**acquiring** scripts on disk and asserts none is reachable
through a CWD-relative path.

This prints each platform's name, enabled/disabled status, and script filename. The router's `PLATFORMS` array is the single source of truth for platform names, required env vars, and auth checks. To add a new platform, add one entry to the array and create the script.

## Scripts

Platform scripts are located at `plugins/soleur/skills/community/scripts/`:

- [community-router.sh](./scripts/community-router.sh) -- Platform dispatch router (single source of truth for platform detection)
- [discord-community.sh](./scripts/discord-community.sh) -- Discord Bot API wrapper (messages, members, guild-info, channels)
- [discord-setup.sh](./scripts/discord-setup.sh) -- Discord credential setup and validation
- [github-community.sh](./scripts/github-community.sh) -- GitHub API wrapper (activity, contributors, discussions, repo-stats)
- [x-community.sh](./scripts/x-community.sh) -- X/Twitter API v2 wrapper (fetch-metrics, fetch-mentions, fetch-timeline, fetch-user-timeline, post-tweet)
- [x-setup.sh](./scripts/x-setup.sh) -- X/Twitter credential setup and validation
- [bsky-community.sh](./scripts/bsky-community.sh) -- Bluesky AT Protocol wrapper (create-session, post, get-metrics, get-notifications)
- [bsky-setup.sh](./scripts/bsky-setup.sh) -- Bluesky credential setup and validation
- [linkedin-community.sh](./scripts/linkedin-community.sh) -- LinkedIn API wrapper (post-content, fetch-metrics stub, fetch-activity stub)
- [linkedin-setup.sh](./scripts/linkedin-setup.sh) -- LinkedIn credential setup, token introspection, and OAuth token generation
- [hn-community.sh](./scripts/hn-community.sh) -- Hacker News Algolia API wrapper (mentions, trending, thread)

## Sub-Commands

### `digest`

Generate a multi-platform community digest. Spawns the `soleur:support:community-manager` agent with digest instructions.

1. Run platform detection
2. Spawn agent: `soleur:support:community-manager` with prompt: "Generate a community digest covering the last 7 days. Enabled platforms: [list]. Collect data from each enabled platform and produce a unified digest."
3. The agent writes the digest to `knowledge-base/support/community/YYYY-MM-DD-digest.md`

**Filename collision with the unattended cron.** The scheduled `cron-community-monitor` writes the same
`knowledge-base/support/community/YYYY-MM-DD-digest.md` name, rendered by its handler from a closed schema (counts and statuses only:
no Top Contributors, Community Interactions or stargazer usernames; #7122). This interactive digest keeps the full contract in the
agent's "Digest File Contract", but running it on a day the cron also publishes **overwrites** the cron's file. Check for today's
file first and confirm the overwrite with the operator when it exists.

If `--headless` is set, skip the Discord posting approval gate (the agent handles this).

### `health`

Display community health metrics across all enabled platforms. Spawns the `soleur:support:community-manager` agent with health instructions.

1. Run platform detection
2. Spawn agent: `soleur:support:community-manager` with prompt: "Display community health metrics. Enabled platforms: [list]. Show metrics from each enabled platform."
3. Metrics are displayed inline (no file output)

### `platforms`

List all platforms with their configuration status. Does NOT spawn an agent -- runs directly.

1. Run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/community-router.sh" platforms`
2. For disabled platforms, **run** the platform's setup script for the operator — do not print
   the command for them to paste. These are execution sites, not display strings: the anchor
   below is loader-substituted for the AGENT, but `CLAUDE_PLUGIN_ROOT` is unset in the
   operator's own shell, so a pasted `bash "${CLAUDE_PLUGIN_ROOT}/…"` resolves to `/skills/…`
   and fails. Run it and relay what it asks for:
   - Discord: Run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/discord-setup.sh"` to configure
   - X/Twitter: Run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/x-setup.sh" validate-credentials` to verify, or run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/x-setup.sh" write-env` to save credentials
   - Bluesky: Run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/bsky-setup.sh" write-env` to save credentials, or run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/bsky-setup.sh" verify` to test
   - LinkedIn: Run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/linkedin-setup.sh" generate-token` to set up credentials, or run `bash "${CLAUDE_PLUGIN_ROOT}/skills/community/scripts/linkedin-setup.sh" verify` to test

### `engage`

Reply to recent mentions on X/Twitter or Bluesky using brand-voice drafts with human approval. Spawns the `soleur:support:community-manager` agent with engagement instructions.

**Platform selection:** The `--platform` flag specifies which platform to engage on. If `--platform` is not provided, use AskUserQuestion to prompt the user to choose from enabled platforms that support engagement (X/Twitter, Bluesky).

The selected platform must be enabled. If not configured, report the missing credentials and stop.

**Flow (X/Twitter):**

1. Run platform detection -- verify X/Twitter is enabled
2. Read the since-id state file (`.soleur/x-engage-since-id`, resolved via `git rev-parse --show-toplevel`). If the file exists and contains a valid numeric ID, pass it as `--since-id` to the fetch command. If missing or non-numeric, skip (fetches last N mentions).
3. Spawn agent: `soleur:support:community-manager` with prompt: "Engage with recent X/Twitter mentions. Use Capability 4: Mention Engagement. Max results: [N]. Since ID: [ID or none]."
4. The agent fetches mentions via `community-router.sh x fetch-mentions`
5. For each mention, the agent drafts a reply following brand guide voice (`knowledge-base/marketing/brand-guide.md` sections `## Voice` and `## Channel Notes > ### X/Twitter`). If the brand guide is missing, the agent warns but proceeds with a professional, declarative tone.
6. Each draft is presented via AskUserQuestion with options:
   - **Accept** -- post this reply via `community-router.sh x post-tweet --reply-to <mention_id>`
   - **Edit** -- modify the reply text (validate 280-character limit; re-prompt if over)
   - **Skip** -- move to the next mention
   - **Skip all remaining** -- end the session (available after the first mention)
7. After all mentions are processed, the agent updates the since-id state file with the `newest_id` from the fetch response and displays a session summary (processed, posted, skipped counts).

**Since-id state file:**

- Path: `.soleur/x-engage-since-id` (relative to repo root)
- Format: plain text, single line containing the tweet ID
- Created on first run with `mkdir -p .soleur && chmod 600` before writing
- Updated only after all mentions are processed (not per-reply)

**Free tier degradation:** If `fetch-mentions` returns 403 (client-not-enrolled), the soleur:support:community-manager agent switches to manual mode — prompting for tweet URLs instead of fetching mentions automatically. The rest of the pipeline (brand-voice draft, approval, post-tweet) runs unchanged. See Capability 4 Step 1b. When the paid tier activates, this fallback is never triggered.

**Flow (Bluesky):**

1. Run platform detection -- verify Bluesky is enabled (`BSKY_HANDLE` + `BSKY_APP_PASSWORD`)
2. Read the cursor state file (`.soleur/bsky-engage-cursor`, resolved via `git rev-parse --show-toplevel`). If the file exists and contains a non-empty value, pass it as `--cursor` to the fetch command.
3. Spawn agent: `soleur:support:community-manager` with prompt: "Engage with recent Bluesky mentions. Use Capability 4: Bluesky Mention Engagement. Limit: [N]. Cursor: [cursor or none]."
4. The agent fetches mentions via `community-router.sh bsky get-notifications`
5. For each mention, the agent drafts a reply following brand guide voice (`knowledge-base/marketing/brand-guide.md` sections `## Voice` and `## Channel Notes > ### Bluesky`). 300-character limit.
6. Same approval flow as X/Twitter (Accept, Edit, Skip, Skip all remaining) but with 300-character validation.
7. Accepted replies posted via `community-router.sh bsky post "<text>" --reply-to-uri <uri> --reply-to-cid <cid>`
8. After processing, the agent updates the cursor state file (`.soleur/bsky-engage-cursor`) and displays a session summary.

**Bluesky cursor state file:**

- Path: `.soleur/bsky-engage-cursor` (relative to repo root)
- Format: plain text, single line containing the cursor string
- Created on first run with `mkdir -p .soleur && chmod 600` before writing
- Updated only after all mentions are processed (not per-reply)

If `--headless` is set, skip all mentions with a summary message ("Skipped N mentions in headless mode -- engage requires interactive approval"). No replies are posted in headless mode.

## Sub-Command Menu

If no sub-command is provided, present options using the AskUserQuestion tool:

**Question:** "Which community operation would you like to run?"

**Options:**

1. **digest** -- Generate a multi-platform community digest
2. **health** -- Display community health metrics
3. **platforms** -- List platform configuration status
4. **engage** -- Reply to recent X/Twitter or Bluesky mentions

## Important Guidelines

- Platform detection runs at the start of every sub-command -- use `community-router.sh platforms` instead of checking env vars directly
- All platform API calls go through `community-router.sh <platform> <command>` -- do not call platform scripts or APIs directly
- The `soleur:support:community-manager` agent handles data collection, analysis, and output formatting
- This skill is the entry point; the agent does the work
- Ownership boundary: community = monitoring + engagement. Broadcasting/distribution is handled by the `social-distribute` skill.
- Posting requires explicit opt-in via environment variables (defense-in-depth guard). Monitoring workflows omit these variables intentionally:
  - LinkedIn: `LINKEDIN_ALLOW_POST=true`
  - X/Twitter: `X_ALLOW_POST=true`
  - Bluesky: `BSKY_ALLOW_POST=true`
- **Scheduled-cron context:** when the monitor runs via the Inngest cron (`apps/web-platform/server/inngest/functions/cron-community-monitor.ts`), a platform is enabled only if its required vars are in BOTH Doppler (`prd_scheduled`) AND the `buildSpawnEnv()` spawn-env allowlist that forwards env to the spawned `claude --print`. A platform shown `disabled` in the digest despite its creds being in Doppler means the allowlist omits them — widen `buildSpawnEnv()`, not the secret store. See `knowledge-base/project/learnings/integration-issues/2026-06-03-platform-disabled-despite-creds-check-spawn-env-allowlist.md`.

## Platform Surface Check

After a new platform is set up and verified via its setup script (confirmed by the `platforms` sub-command showing `[enabled]`), check whether the platform has been added to all public-facing surfaces. Read each file and verify:

| File | What to look for |
|------|------------------|
| `plugins/soleur/docs/_data/site.json` | URL entry for the platform |
| `plugins/soleur/docs/pages/community.njk` | Card in the Connect section |
| `knowledge-base/marketing/brand-guide.md` | Platform handle mention |

If any surface is missing, output a warning:

```text
[WARNING] Platform <platform-name> is missing from: <list-of-files>.
These files need updating before the integration is complete.
Consider filing: gh issue create --title 'feat(docs): add <platform-name> to website and brand guide' --milestone 'Post-MVP / Later'
```

This check does not block provisioning -- it is advisory only. The soleur:operations:ops-provisioner agent has a broader version of this check for non-community tools.

Files in this skill

  • SKILL.md10.7 KB
  • scripts/bsky-community.sh11.3 KB
  • scripts/bsky-setup.sh6 KB
  • scripts/community-router.sh2.7 KB
  • scripts/discord-community.sh7.5 KB
  • scripts/discord-setup.sh10.1 KB
  • scripts/github-community.sh10.3 KB
  • scripts/hn-community.sh5.5 KB
  • scripts/linkedin-community.sh11.1 KB
  • scripts/linkedin-setup.sh11.2 KB
  • scripts/x-community.sh20.5 KB
  • scripts/x-setup.sh9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.