The interns-mcp source lives inside the `OpeItcLoc03/common` monorepo (at ~/projects/.common/), not as a separate `interns-mcp` repo on Gitea. The previous commit incorrectly wrote `git clone .../interns-mcp`. Now the clone-fallback correctly: - If ~/projects/.common/.git exists but lib/interns-mcp/ is missing: git -C ~/projects/.common pull --ff-only (stale clone, needs fresh subdirs) - If ~/projects/.common/ is absent: git clone .../common.git ~/projects/.common (fresh clone of monorepo) - Added "wrong repo" to Common mistakes section - Added monorepo scope note to Out of scope section Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
16 KiB
name, version, description
| name | version | description |
|---|---|---|
| setup-interns | 0.3.0 | Installs and configures the local `interns` MCP server — clones the repo to `~/projects/.common/lib/interns-mcp/` (or uses an existing clone), `pip install -e` it, writes `~/projects/.common/secrets/interns.env` with endpoint API keys, and registers `mcpServers.interns` in `~/.claude.json`. Use this skill when the user says "install interns", "set up interns", "configure interns", "настрой интернов", "установи интернов", "interns не работает", "interns isn't working", or whenever the `mcp__interns__*` tools are missing in a session that needs delegation. Cross-platform — Windows / Linux / macOS. Mutates user-level config and writes secrets; pauses for confirmation before every write. |
setup-interns
One-time skill that gets the local
internsMCP server running with the user's endpoint API keys and a registeredmcpServers.internsentry in~/.claude.json. Stops at confirmation gates because the procedure runspip install, writes a secret-bearing.envfile, and edits user-level config.
Reference: full design lives in this repo at .wiki/concepts/interns-design.md (Layer 1/2/3 architecture, MVP catalog, always-ask paths, routing hints).
When to use
- User explicitly asks: install / set up / configure interns.
- A
using-interns-driven task fails becausemcp__interns__*tools aren't available in the session. - New machine in the user's multi-machine fleet — install once per machine that wants delegation.
- Migrating a stale install (endpoint key rotated, server source moved, broken
dist/artifact) — same procedure, Phase 1 detects what's already in place.
Out of scope
- Issuing or rotating endpoint API keys (Ollama Cloud, OpenRouter, etc.). The skill uses keys the user already has; if there is none, it points at the provider's settings page and stops.
- Running
interns-mcpitself — the Claude Code harness spawns it on session start. - Authoring new interns or editing
~/projects/.common/config/interns/config.yaml— that's a content task, not a setup task. - Any other MCP server.
- Setting up the entire
commonmonorepo beyond whatinterns-mcpneeds. The clone step gets the full monorepo (it also containsprojects-meta-mcpand other shared tools), but this skill only verifies thelib/interns-mcp/subdirectory.
Hard rule: don't auto-mutate config
The procedure runs pip install, writes ~/projects/.common/secrets/interns.env (carries endpoint API keys), and edits ~/.claude.json. Always pause for explicit confirmation between Phase 1 (discovery, read-only) and Phase 2 (plan), and again before Phase 3 (backup + writes). A trigger phrase grants permission to inspect, not to install or write secrets.
Procedure
Phase 0 — Environment sanity
- Confirm Claude Code is the current harness (need
mcpServersregistration in~/.claude.json). - Confirm
python≥ 3.11 andpipare onPATH. Report the resolved interpreter path (python -c "import sys; print(sys.executable)"); the skill will pin this exact path in the MCP registration so a laterpythonshadowed by another env doesn't silently take over. - Confirm
nodeis onPATH(node --version). Therepo_readintern runsnpx repomix@latestas a subprocess. Ifnodeis absent, the user must install Node.js 20+ before proceeding —repo_readcalls will fail at runtime with a clear "node not found" error. - (Optional, recommended) Pre-warm the repomix binary:
npx --yes repomix@latest --version. This caches the package so the first realrepo_readcall is instant (5–10s first-run penalty avoided). Skip silently on failure — the call will just be slower the first time. - Confirm network reachability to the configured endpoints (default:
https://ollama.com/v1). On HTTP 401 / 403 later, the API key is dead — stop and ask for a new one. - Confirm
gitis onPATH(needed for clone-fallback in Phase 4 if the source isn't already present). - Pick paths:
~/projects/.common/lib/interns-mcp/(source),~/projects/.common/config/interns/config.yaml(catalog),~/projects/.common/secrets/interns.env(keys, gitignored),~/.claude.json(MCP registration). POSIX-style paths resolve correctly under git-bash on Windows.
Phase 1 — Discovery (read-only)
Search, in order. Report only "found at ", never echo key values.
Server source. Check whether ~/projects/.common/lib/interns-mcp/pyproject.toml exists.
- If present → report "found at ~/projects/.common/lib/interns-mcp/". Phase 4 will
pip install -e(or skip if already importable). - If absent → check whether
~/projects/.common/.gitexists (thecommonmonorepo).- If the monorepo exists but the subdirectory is missing → report "source subdir absent — will git pull". Phase 4 will
git -C ~/projects/.common pull --ff-onlyto fetch the latest content, then verify the subdirectory appeared. - If the monorepo is absent → report "source not found — will clone common monorepo from gitea". Phase 4 will
git clone https://git.kzntsv.site/OpeItcLoc03/common.git ~/projects/.common.
- If the monorepo exists but the subdirectory is missing → report "source subdir absent — will git pull". Phase 4 will
If clone or pull fails (no network, no Gitea PAT), stop with a clear message:
Failed to clone/pull the common monorepo. Options:
1. Check network access to https://git.kzntsv.site
2. If you need a Gitea PAT: https://git.kzntsv.site/user/settings/applications
(scope: read:repository is sufficient)
3. If Gitea is unreachable, re-run setup-interns when it's back.
Build artifact. Run python -c "import interns_mcp" 2>&1 against the candidate interpreter. If it fails with ModuleNotFoundError, Phase 4 will run pip install -e ~/projects/.common/lib/interns-mcp/. If it succeeds, capture the installed location and skip the install in Phase 4.
Config catalog. Read ~/projects/.common/config/interns/config.yaml. Extract the unique set of endpoints.<name>.api_key_env values — these are the env var names the runtime expects to find. Capture for Phase 2.
Existing endpoint keys. Look in priority order, per api_key_env name from the config:
~/projects/.common/secrets/interns.env(<NAME>=...lines).- Process env (
os.environ[<NAME>]). ~/.config/projects-mcp/auth.toml— only if the user has explicitly noted the key is shared with another local MCP server (rare).
The first hit wins per key. Never echo key values in chat.
MCP registration. Read ~/.claude.json and check mcpServers.interns. Note the command and args. If args point at a stale interpreter, Phase 6 will fix it.
Gitignore sanity. Check ~/projects/.gitignore. If .common/secrets/ (or .common/secrets/*.env) is not listed, flag for Phase 2 — the skill will offer to add it before writing the file.
Phase 2 — Plan + confirm
Present a single-block plan to the user:
Source: <found at ~/projects/.common/lib/interns-mcp/ | will clone/pull common monorepo>
Module: <interns_mcp importable | will pip install -e>
Config: <found at ~/projects/.common/config/interns/config.yaml> — endpoints: <names>
Missing keys: <list of <NAME> not yet present in interns.env | none>
Gitignore: <covers .common/secrets/ | will add ".common/secrets/*.env">
MCP entry: <present in ~/.claude.json | will add | will fix interpreter path>
Backups: ~/.claude.json.bak-<ts>, ~/projects/.common/secrets/interns.env.bak-<ts> (if exists)
Wait for explicit confirmation ("ok", "go", "поехали"). Anything else → stop.
For each missing key, ask: "Paste a value for <NAME> (endpoint: <endpoint_name> — provider settings page: <url-from-config-or-known-list>), or skip and we'll leave the entry blank for you to fill later." Don't proceed past Phase 2 without resolving every required key — the runtime won't start with a missing API key.
Phase 3 — Backup
Copy each file we will modify to <file>.bak-YYYYMMDD-HHMMSS:
TS=$(date +%Y%m%d-%H%M%S)
[ -f ~/.claude.json ] && cp ~/.claude.json ~/.claude.json.bak-$TS
[ -f ~/projects/.common/secrets/interns.env ] && cp ~/projects/.common/secrets/interns.env ~/projects/.common/secrets/interns.env.bak-$TS
Confirm both backups exist (when their source existed) before any further edit.
Phase 4 — Clone (if needed) + Install Python module
Clone or pull. If Phase 1 found the source absent:
if [ -d ~/projects/.common/.git ]; then
# Monorepo exists but subdirectory missing — pull latest
git -C ~/projects/.common pull --ff-only
else
# Fresh clone of the common monorepo
mkdir -p ~/projects
git clone https://git.kzntsv.site/OpeItcLoc03/common.git ~/projects/.common
fi
Verify ~/projects/.common/lib/interns-mcp/pyproject.toml exists after clone/pull. If the subdirectory is still missing after pull — the interns-mcp module may not have been pushed to the monorepo yet. Abort with a clear message.
If the source was already present and Phase 1 found interns_mcp importable, skip both clone/pull and install.
Install. If Phase 1 found interns_mcp not importable:
python -m pip install -e ~/projects/.common/lib/interns-mcp/
Capture the resolved python from Phase 0; use the same interpreter for both pip install and the later MCP command: field. Verify post-install:
python -c "import interns_mcp; print(interns_mcp.__file__)"
If import fails — abort. Ask the user to paste the pip install output so the failure mode is visible.
Phase 5 — Write interns.env + gitignore
If Phase 1 flagged a missing .gitignore rule, append it first:
# interns endpoint API keys
.common/secrets/*.env
Then write ~/projects/.common/secrets/interns.env. Per-key behavior:
- Existing key in the file with a non-empty value — leave it alone.
- Missing key — append
<NAME>=<value-from-Phase-2>if the user pasted one, or<NAME>=(blank) if the user skipped. A blank entry will fail at runtime with a clearKeyError; that's acceptable for the "I'll fill it later" path.
Permissions: on Linux / macOS run chmod 600 ~/projects/.common/secrets/interns.env. On Windows the default ACL is per-user, no extra step.
Phase 6 — Register in ~/.claude.json
Edit ~/.claude.json. Add or update the mcpServers.interns block:
{
"mcpServers": {
"interns": {
"command": "<ABSOLUTE_PATH_TO_PYTHON>",
"args": ["-m", "interns_mcp.server"],
"cwd": "~/projects"
}
}
}
cwd is set so the runtime resolves .common/config/interns/config.yaml and .common/secrets/interns.env relative to the ~/projects base directory regardless of where Claude Code was launched. On Windows, expand ~/projects to the absolute path (e.g. C:/Users/<USER>/projects).
Absolute interpreter path comes from Phase 0 (sys.executable). Forward slashes work in JSON on Windows without escaping.
After each edit, validate JSON:
# Windows (git-bash)
powershell.exe -NoProfile -c "Get-Content '<file>' -Raw | ConvertFrom-Json | Out-Null"
# Linux / macOS
jq empty <file>
# fallback
python -c "import json; json.load(open('<file>'))"
If validation fails → restore from .bak-* and abort.
Phase 7 — Smoke test (best-effort)
Best-effort: ask the user to call mcp__interns__bulk_text_read against a tiny benign input (e.g. read this file's Phase 7 section, ask "what is this section about?"). A response that is structurally valid (text + usage) means the server is reachable.
Important caveat to relay to the user: in the same session that just ran setup, the active MCP connection was bound at session start. So a passing in-session smoke test only proves "an interns server is alive" — not "the registration we just wrote is what's serving it". The real test is after Claude Code restart.
If mcp__interns__* tools aren't registered in this session at all, skip the smoke test and rely on Phase 8.
Phase 8 — Restart guidance + final report
Tell the user:
Setup complete. Restart Claude Code so the new mcpServers.interns
registration binds to a fresh stdio session.
After restart:
• mcp__interns__* tools serve from <python> -m interns_mcp.server
• Source at ~/projects/.common/lib/interns-mcp/
• Endpoint keys live in ~/projects/.common/secrets/interns.env (gitignored)
• Config catalog at ~/projects/.common/config/interns/config.yaml
• Backups saved at ~/.claude.json.bak-<ts> (and interns.env.bak-<ts>
if it existed before)
Runtime policy lives in `using-interns`. CLAUDE.md trigger:
delegate to interns when allowed
project-bootstrap 1.6.0+ adds it to new projects automatically.
If something breaks after restart:
• Restore from .bak-* and tell me — we'll roll back together.
Rollback procedure
If a problem surfaces (now or after restart):
- Stop. Don't try to fix forward.
- Find the most recent
.bak-YYYYMMDD-HHMMSSnext to~/.claude.json(and~/projects/.common/secrets/interns.envif applicable). cp <file>.bak-<ts> <file>for each.- Optional:
pip uninstall interns-mcpif you want to remove the editable install. - Optional:
rm -rf ~/projects/.common/lib/interns-mcpif you want to remove the cloned source. - Restart Claude Code.
- Confirm
mcp__interns__*is gone (or back to its pre-existing version). - Report what went wrong so we can fix the procedure.
Cross-platform notes
The procedure is platform-agnostic. Only auxiliary tooling differs:
| JSON validate | Backup | Permissions on .env |
|
|---|---|---|---|
| Windows (git-bash) | powershell.exe -NoProfile -c "Get-Content '<f>' -Raw | ConvertFrom-Json | Out-Null" |
cp |
per-user ACL by default |
| Linux | jq empty <f> (or python -c "import json; json.load(open('<f>'))") |
cp |
chmod 600 |
| macOS | same as Linux | cp |
chmod 600 |
Path forms (~/projects/.common/..., ~/.config/..., ~/.claude.json) are identical on all three.
Common mistakes
- Skipping Phase 1. "User just said 'install interns' — let's go." No — find existing source / module / keys first; clobbering an existing
.envover a working one loses keys you can't recover. - Echoing endpoint keys. They're secrets. Edit / Write tool calls inevitably contain them (that's how they land in
.env), but no chat output should. - Pinning
pythoninstead of<sys.executable>. A barepythonin the MCPcommand:resolves to whatever interpreter is first onPATHat session start — often a different env without theinterns_mcpmodule. Always use the absolute interpreter path captured in Phase 0. - Forgetting
cwd: ~/projects. Without it the runtime can't find.common/config/interns/config.yamland bombs at startup with a config-not-found error that looks like a Claude Code bug. - Writing
.envwith0644perms on Linux/macOS. Token leak. Alwayschmod 600after write. - Missing the gitignore rule. Tokens commit to the repo on the next
git add .. Always check.gitignorecovers.common/secrets/*.envbefore writing — Phase 5 does it but it's worth double-checking. - Treating in-session smoke test as proof. Same as the context7 / projects-meta caveat — the active MCP connection was bound at session start. Real verification happens after restart.
- Auto-running on every "use interns". This skill is intrusive. Trigger only on explicit "install / set up / configure interns", or when MCP tools are missing and the user is blocked.
- Cloning over an existing source directory. If
~/projects/.common/lib/interns-mcp/already exists withpyproject.toml, don't clone — use what's there. Clone is only for the "source not found" case. - Cloning the wrong repo.
interns-mcplives inside thecommonmonorepo atOpeItcLoc03/common.git, not as a separateinterns-mcprepo. Always clonecommon.gitand verify the subdirectory.