feat: add Claude Code project-mode support#113
Open
GuyNachshon wants to merge 1 commit intohuggingface:mainfrom
Open
feat: add Claude Code project-mode support#113GuyNachshon wants to merge 1 commit intohuggingface:mainfrom
GuyNachshon wants to merge 1 commit intohuggingface:mainfrom
Conversation
Adds Claude Code as a second frontend alongside the standalone `ml-intern` CLI.
Both share the same tools under `agent/tools/` — no duplication, no changes to
agent runtime behavior.
What's new:
- `packages/mcp_server/server.py` — MCP server that re-exposes `agent/tools/*`
to Claude Code via stdio. Uses `mcp.server.lowlevel.Server` to preserve the
existing JSON schemas verbatim (FastMCP 3.x re-derives schemas from Python
type hints, which would lose `oneOf`/operation-discriminated structures).
- `CLAUDE.md` — system prompt ported from `agent/prompts/system_prompt_v3.yaml`,
with `plan_tool` → TodoWrite and the `research` tool → Task subagent
substitutions noted.
- `.claude/agents/research.md` — research subagent (read-only HF tool subset).
- `.claude/commands/{ml-intern,research,inspect-dataset,finetune,run-job}.md`
- `.claude/hooks/`:
- `pre_tool_use_approval.py` — port of `_needs_approval` from
`agent/core/agent_loop.py`. Fail-safe on malformed input (forces a prompt
rather than silently allowing).
- `session_start_context.py` — injects HF username + local-mode banner.
- `session_end_upload.py` — uploads transcripts to
`smolagents/ml-intern-sessions` after running through `agent/core/redact.py`.
- `CLAUDE_CODE_GUIDE.md` — user docs.
- `.gitignore` — switch from blanket `.claude/` to specific exclusions
(`.claude/settings.local.json`, `__pycache__`) so shared config is tracked
but per-user overrides are not.
What's *not* changed:
- `agent/` is untouched. The standalone CLI still works exactly as before.
- No new Python deps. The MCP server uses `mcp` and `fastmcp` already in
`pyproject.toml`.
Behavior parity vs. standalone CLI (env var → `Config` field):
ML_INTERN_YOLO → yolo_mode (default 0)
ML_INTERN_CONFIRM_CPU_JOBS → confirm_cpu_jobs (default 1)
ML_INTERN_SAVE_SESSIONS → save_sessions (default 1)
ML_INTERN_SESSION_REPO → session_dataset_repo (default smolagents/ml-intern-sessions)
ML_INTERN_LOCAL_MODE → --local (default 0)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: add Claude Code project-mode support
Summary
Adds Claude Code as a second frontend alongside the standalone
ml-internCLI. Both share the same tools underagent/tools/— no duplication, no changes to the agent runtime.After this PR, running
claudefrom the repo root works:What's new
packages/mcp_server/server.pyagent/tools/*to Claude Code via stdio. Usesmcp.server.lowlevel.Serverto preserve existing JSON schemas verbatim — FastMCP 3.x re-derives schemas from Python type hints, which would loseoneOf/operation-discriminated structures.CLAUDE.mdagent/prompts/system_prompt_v3.yaml.plan_toolreferences → TodoWrite.researchtool → Task subagent..claude/agents/research.mdresearch_tool— its own context, restricted to read-only HF tools)..claude/commands/{ml-intern,research,inspect-dataset,finetune,run-job}.mdCLAUDE.mdmethodology..claude/hooks/pre_tool_use_approval.py_needs_approvalfromagent/core/agent_loop.py. Fail-safe: malformed payloads, non-dicttool_input, and emptytool_nameall force a prompt instead of silent allow..claude/hooks/session_start_context.pyhuggingface_hub.HfApi.whoami()) and a local-mode banner so the model knows the user's HF namespace and whether to expect a sandbox. Mirrorsagent/context_manager/manager.py..claude/hooks/session_end_upload.pysmolagents/ml-intern-sessionsafter running throughagent/core/redact.py::scrub. Refuses paths outside~/.claude/or$CLAUDE_PROJECT_DIR.CLAUDE_CODE_GUIDE.md.gitignore.claude/to specific exclusions (.claude/settings.local.json,__pycache__) so shared project config is tracked but per-user overrides are not.What's not changed
agent/is untouched. The standaloneml-internCLI works exactly as before.mcpandfastmcpalready inpyproject.toml.Behavior parity vs. standalone CLI
Configfieldyolo_modeML_INTERN_YOLO0confirm_cpu_jobsML_INTERN_CONFIRM_CPU_JOBS1save_sessionsML_INTERN_SAVE_SESSIONS1session_dataset_repoML_INTERN_SESSION_REPOsmolagents/ml-intern-sessions--localML_INTERN_LOCAL_MODE0What's intentionally not ported
/help,/compact,/model,/yolo,/effort,/status,/undo— Claude Code has natives or these are model-loop concepts (/effort,/modelprobe) that don't apply.record_llm_call,record_hf_job_*,record_sandbox_*,HeartbeatSaver— Claude Code's transcript persistence covers the externally-visible behavior (don't lose data on long turns).auto_save_interval,heartbeat_interval_s,max_iterations,reasoning_effort,prompt_caching,effort_probe,model_switcher,hf_router_catalog— Claude Code provides equivalents.private_hf_repo_tools— already disabled upstream (agent/core/tools.py:55-58).Test plan
uv run python -m packages.mcp_server.server < /dev/nullboots cleanly (15 tools register: 10 HF tools + 4 sandbox tools +sandbox_create).tool_name, non-dicttool_input(all forceask).push_to_hubwhenML_INTERN_CONFIRM_CPU_JOBS=0.from_pretrainedwithoutpush_to_hubwarning in the prompt reason.HF_TOKENis set; reports specific failure mode (no token vs whoami HTTP error vs other) when not.hf_…,sk-ant-…,sk-…,gh*_…,Bearer …, andKEY=valueexports before upload (verified against planted secrets).~/.claude/or$CLAUDE_PROJECT_DIR.ml-internCLI continues to work unchanged.tests/unit/(excluding pre-brokentest_user_quotas.pywhich lackspytest-asyncio) passes 46/46.Anticipated review feedback
mcp.server.lowlevel.Serverinstead of FastMCP?" Documented in the docstring at top ofserver.py. FastMCP 3.x derives input schemas from Python type hints; the existing*_TOOL_SPEC["parameters"]JSON schemas inagent/tools/useoneOf/operation-discriminated structures that don't round-trip through that.Eventchannel was aSession-scoped abstraction without a Claude Code analog..gitignorechange might affect existing users." Only affects users who had local-only files in.claude/(rare — that directory was previously fully ignored, so anything there was either accidental or intentional opt-out). The new rules track everything exceptsettings.local.json(Claude Code's standard local-only override file) and runtime caches.Follow-up
The plugin packaging (separate
plugin/directory, vendored library, marketplace manifest) is the next PR. This one stops at "the repo works as a Claude Code project."