Files
claude-skills/skills/setup-interns/SKILL.md
vitya ef3d38e79d feat(setup-interns, using-interns): secrets at ~/.config/projects-secrets/
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>
2026-05-21 14:22:51 +03:00

250 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: setup-interns
version: 0.4.0
description: 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 `interns` MCP server running with the user's endpoint API keys and a registered `mcpServers.interns` entry in `~/.claude.json`. Stops at confirmation gates because the procedure runs `pip install`, writes a secret-bearing `.env` file, 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 because `mcp__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-mcp` itself — 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 `common` monorepo beyond what `interns-mcp` needs. The clone step gets the full monorepo (it also contains `projects-meta-mcp` and other shared tools), but this skill only verifies the `lib/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 `mcpServers` registration in `~/.claude.json`).
- Confirm `python` ≥ 3.11 and `pip` are on `PATH`. 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 later `python` shadowed by another env doesn't silently take over.
- Confirm `node` is on `PATH` (`node --version`). The `repo_read` intern runs `npx repomix@latest` as a subprocess. If `node` is absent, the user must install Node.js 20+ before proceeding — `repo_read` calls 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 real `repo_read` call is instant (510s 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 `git` is on `PATH` (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 <path>", 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/.git` exists (the `common` monorepo).
- 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-only` to 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 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:
1. `~/.config/projects-secrets/interns.env` (`<NAME>=...` lines).
2. Process env (`os.environ[<NAME>]`).
3. `~/.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`:
```bash
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:
```bash
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:
```bash
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:
```bash
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 clear `KeyError`; 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:
```json
{
"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:
```bash
# 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):
1. Stop. Don't try to fix forward.
2. Find the most recent `.bak-YYYYMMDD-HHMMSS` next to `~/.claude.json` (and `~/.config/projects-secrets/interns.env` if applicable).
3. `cp <file>.bak-<ts> <file>` for each.
4. Optional: `pip uninstall interns-mcp` if you want to remove the editable install.
5. Optional: `rm -rf ~/projects/.common/lib/interns-mcp` if you want to remove the cloned source.
6. Restart Claude Code.
7. Confirm `mcp__interns__*` is gone (or back to its pre-existing version).
8. 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 `.env` over 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 `python` instead of `<sys.executable>`.** A bare `python` in the MCP `command:` resolves to whatever interpreter is first on `PATH` at session start — often a different env without the `interns_mcp` module. Always use the absolute interpreter path captured in Phase 0.
- **Forgetting `cwd: ~/projects`.** Without it the runtime can't find `.common/config/interns/config.yaml` and bombs at startup with a config-not-found error that looks like a Claude Code bug.
- **Writing `.env` with `0644` perms on Linux/macOS.** Token leak. Always `chmod 600` after 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 with `pyproject.toml`, don't clone — use what's there. Clone is only for the "source not found" case.
- **Cloning the wrong repo.** `interns-mcp` lives inside the `common` monorepo at `OpeItcLoc03/common.git`, not as a separate `interns-mcp` repo. Always clone `common.git` and verify the subdirectory.