Multi-Source Content Summarizer Skill
A local-first Codex Skill and MCP server that summarizes authorized Baidu Netdisk files, local audio/video, public Bilibili videos, X posts, and web articles. It produces a complete Obsidian source note, topic knowledge cards with bidirectional links, timestamped citations, retained key screenshots, and an idempotent Feishu digest for the following morning at 10:00 Asia/Shanghai.
Source media is copied or downloaded into a private job cache. Successful jobs delete temporary media only after Obsidian publication and attachment verification. Failed jobs retain their owned artifacts for 24 hours for diagnosis or retry. Original sources are never deleted.
Requirements
- Node.js 22.13.0 or newer.
ffmpegandffprobefor audio/video processing.yt-dlponly for Bilibili ingestion.- Optional system
tesseractplus the exact language data you need; missing OCR does not block other capabilities. - An authorized Obsidian vault directory. The cache must be outside the vault, and neither directory may contain the other.
- API credentials only for capabilities you enable.
Fresh-clone installation
git clone https://github.com/xbackhome/multi-source-content-summarizer-skill.git
cd multi-source-content-summarizer-skill
npm ci
npm run build
npm run setup
npm run doctor -- --json
npm run setup writes non-secret settings to mscs.config.yaml and secrets to the gitignored .env. Review the generated cacheRoot and obsidian.vaultPath. If the project is inside your vault, move cacheRoot to a separate directory before starting a worker.
Install the Skill metadata into your Codex home, then restart Codex so it is rediscovered:
$codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME ".codex" }
$destination = Join-Path $codexHome "skills\multi-source-content-summarizer"
New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null
Copy-Item -Recurse -Force .\skills\multi-source-content-summarizer $destination
Re-run the copy after updating the repository. The MCP runtime remains in the cloned repository; the installed Skill contains the workflow and setup reference that tell Codex when and how to call it.
Choose openai or openai-compatible independently for transcription, vision, and summary. Setup explicitly asks whether to use one shared AI key (AI_API_KEY) or separate TRANSCRIPTION_API_KEY, VISION_API_KEY, and SUMMARY_API_KEY values. Each secret is collected with terminal echo suppressed, preserved on rerun unless replaced, and never written to YAML. Setup is explicitly unverified until mscs doctor succeeds; do not process sources before that check. Each capability keeps its own model ID and optional HTTPS baseUrl, so later providers can be added behind the existing capability interfaces without changing the job pipeline.
The doctor exits successfully when optional external capabilities are not configured and reports them as disabled. An enabled capability that fails authentication, binary, filesystem, or endpoint checks is reported as failed.
Start the system
Open separate terminals in the repository:
npm run worker
npm run mcp
npm run digest -- schedule
The bundled runtime reads mscs.config.yaml and .env; MSCS_RUNTIME_MODULE is no longer required. Advanced users may still set it to an absolute, reviewed, real .js, .mjs, or .cjs module that exports createMscsRuntime. Symlinks, junctions, relative paths, and other extensions are rejected.
Manual digest recovery:
npm run digest -- preview 2026-07-15
npm run digest -- send 2026-07-15
npm run digest -- send 2026-07-15 --retry-terminal
The Shanghai date D is delivered on D+1 at 10:00. Empty days are skipped. Delivery, file upload, and cleanup have durable receipts and bounded retry; use --retry-terminal only after fixing the recorded configuration or permission problem.
Connect Codex over MCP
Codex local clients share ~/.codex/config.toml; a trusted project may instead use .codex/config.toml. Configure the built STDIO entry point:
[mcp_servers.multi-source-content-summarizer]
command = "node"
args = ["/absolute/path/to/multi-source-content-summarizer-skill/dist/bin/mcp.js"]
cwd = "/absolute/path/to/multi-source-content-summarizer-skill"
env_vars = ["AI_API_KEY", "TRANSCRIPTION_API_KEY", "VISION_API_KEY", "SUMMARY_API_KEY", "BAIDU_ACCESS_TOKEN", "X_USER_ACCESS_TOKEN", "FEISHU_APP_SECRET"]
Or add the server with the CLI:
codex mcp add multi-source-content-summarizer -- node C:\absolute\path\multi-source-content-summarizer-skill\dist\bin\mcp.js
codex mcp list
Restart the Codex client after editing configuration and verify with /mcp or codex mcp list. Available tools inspect sources, create/list/retry jobs, clean owned job caches, and preview/send digests.
Sources and credentials
- Local file: pass an absolute path with
kind: "local". Only supported regular audio/video files are copied; relative paths, symlinks, junctions, and unsupported extensions are rejected. - Baidu Netdisk: create a Baidu developer application and register one exact fixed loopback callback such as
http://127.0.0.1:53682/oauth/baidu/callback. Complete the authorization-code flow in the official app, request read-only scopes, then store only the resulting access token asBAIDU_ACCESS_TOKEN. Usebaidu:path:/folder/video.mp4orbaidu:file:123456. Text, PDF, and DOCX primary files or accessible same-name note sidecars bypass FFmpeg; PDF/DOCX extraction is local and bounded by file, page, ZIP-entry, decompression, and text limits. - Bilibili: install
yt-dlp; only public Bilibili ingestion is shipped in version 1. Platform subtitles are parsed directly into timestamped segments. When screenshots are requested, verified public media is also downloaded within the configured size bound and used only for frame evidence; with screenshot policynone, subtitle-first jobs do not download media. This release does not support authenticated Bilibili sessions or cookies. - X: use an OAuth 2.0 PKCE user-context token with
tweet.readandusers.readasX_USER_ACCESS_TOKEN. Thread acquisition keeps only posts by the root author and excludes third-party replies. Attached X media is retained as bounded, untrusted metadata-only context; version 1 does not download X media. - Web: only public HTTP(S) articles are accepted; redirects, DNS results, response size, login/paywall signals, and SSRF targets are checked.
Detailed least-privilege setup and troubleshooting are in the setup reference.
Obsidian output
Each completed source produces Sources/*.md, Cards/*.md, and content-hashed attachments/evidence-* inside the authorized vault (or staging root). Notes distinguish synthesis from provenance, preserve timestamp links, embed retained screenshots, and add only validated bidirectional card links. Existing notes are replaced only for the same stable source identity and are verified byte-for-byte before success is recorded.
Feishu delivery
Recommended app-bot mode requires an App ID, App Secret, target chat_id or open_id, bot availability, and only im:message:send_as_bot plus im:resource. Optional lark-cli-user mode requires a separately installed/authenticated lark-cli, lark-cli auth status --verify, and only im:message plus im:message.send_as_user. Secrets remain in .env or the tool's own credential store.
Create a Windows scheduled task from an elevated PowerShell prompt if you prefer one daily process instead of the resident scheduler:
$project = (Get-Location).Path
$node = (Get-Command node).Source
$script = (Resolve-Path .\dist\bin\digest.js).Path
$command = "& '$node' '$script' send ((Get-Date).AddDays(-1).ToString('yyyy-MM-dd'))"
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument ('-NoProfile -NonInteractive -Command "{0}"' -f $command) -WorkingDirectory $project
$trigger = New-ScheduledTaskTrigger -Daily -At 10:00AM
Register-ScheduledTask -TaskName "MSCS-Feishu-Digest" -Action $action -Trigger $trigger -Description "Send the prior Shanghai-day content digest" -Force
The machine must use the Asia/Shanghai timezone for the Windows trigger. The application also fixes digest calendar calculation to Asia/Shanghai.
Tests and capability skips
npm run validate:skill
npm run build
npm test
npm run test:e2e
E2E tests generate a license-safe 20-second video at runtime and use local deterministic AI doubles; they never call external services. They skip only when FFmpeg/ffprobe is unavailable. CI installs FFmpeg on Windows and Ubuntu, so E2E runs there.
Privacy and policy limits
Use only sources and destinations you are authorized to access. This project is not a crawler bypass, cookie extractor, DRM remover, CAPTCHA solver, or paywall circumvention tool. Treat AI output as generated synthesis and verify consequential claims against retained evidence. Logs and public MCP responses omit API keys, cookies, signed URLs, local source paths, and raw digest content.
Troubleshooting
doctorshows disabled: run setup again or enable only the required connector and credential.doctorshows a model warning: model listing succeeded, but the selected audio/image/text modality still needs a real probe.- Worker says configuration failed: verify
mscs.config.yaml,.env, separate cache/vault roots, and API keys. - No screenshots: install FFmpeg; install Tesseract language data only if OCR is required.
- Bilibili unavailable: verify
yt-dlp --version, source authorization, and public availability. - Feishu retry is terminal: correct app scopes, availability range, bot membership/target ID, or
lark-cliauthentication, then use the explicit terminal retry command.
Licensed under the MIT License.