Aligns claude-skills with secrets-out-of-common etap-1 migration: the canonical home for plain-text local-dev secrets is now ~/.config/projects-secrets/, outside any git tree. setup-interns [v0.3.0 → v0.4.0, MINOR — write target changed]: - Phase 1 drops gitignore-sanity check (no longer needed) - Phase 2 plan block drops Gitignore line - Phase 3 backs up ~/.config/projects-secrets/interns.env if present - Phase 5 writes ~/.config/projects-secrets/interns.env (mkdir -p ahead) - Phase 6 cwd documentation: secrets path no longer relative to cwd; uses INTERNS_SECRETS_PATH env var (or ~/.config default) — independent - Common-mistakes drops "missing gitignore rule" entry using-interns [v0.2.0 → v0.2.1, PATCH — wording]: - Always-ask paths section reflects new canonical secrets home - Prerequisites text updates setup-interns write target interns-design.md (wiki concept): path refs updated for ASCII layer diagram, Layer 1 example block, Phase 5 description, comparison table, and final cross-cutting note. **/projects-secrets/** added to always-ask documentation pattern. dist/: setup-interns.skill + using-interns.skill rebuilt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 KiB
name, version, description
| name | version | description |
|---|---|---|
| setup-interns | 0.4.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 `~/.config/projects-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 ~/.config/projects-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),~/.config/projects-secrets/interns.env(keys, outside any git tree),~/.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:
~/.config/projects-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.
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>
MCP entry: <present in ~/.claude.json | will add | will fix interpreter path>
Backups: ~/.claude.json.bak-<ts>, ~/.config/projects-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 ~/.config/projects-secrets/interns.env ] && cp ~/.config/projects-secrets/interns.env ~/.config/projects-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
Write ~/.config/projects-secrets/interns.env (parent dir mkdir -p ~/.config/projects-secrets if missing). The file lives outside any git tree, so no .gitignore rule is needed. 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 ~/.config/projects-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 relative to the ~/projects base directory regardless of where Claude Code was launched. Secrets are loaded from ~/.config/projects-secrets/interns.env (overridable via INTERNS_SECRETS_PATH env var) — independent of cwd. 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 ~/.config/projects-secrets/interns.env (outside any git tree)
• 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~/.config/projects-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. - 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.