Source code for milp_flare.harness.claude_code
import json
import os
import shutil
from pathlib import Path
from typing import Any
from milp_flare._assets import MCP_JSON, SCRIPTS_DIR, SKILLS_DIR
from milp_flare.harness.base import Harness
_TEMPLATE: str = (SCRIPTS_DIR / "claude_code_agent.sh").read_text()
[docs]
class ClaudeCodeHarness(Harness):
"""Claude Code agent harness for FLARE.
Use the :claude:`Claude Code CLI </>` as an agent harness. Authentication
is provided by a long-lived OAuth token (``CLAUDE_CODE_OAUTH_TOKEN``) generated
via ``claude setup-token`` and is billed against a Claude subscription. See
:ref:`harness-claude-code` for setup instructions.
.. warning::
Starting June 15, 2026, Claude Agent SDK and claude -p usage no longer
counts towards the Claude plan's usage limits. It will instead charge a
separate Agent SDK monthly credit. See
`this article <https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan>`_.
Parameters
----------
model : str
Claude model identifier. Only supports models that are supported by the
Claude Code CLI (e.g., ``"claude-opus-4-7"``, ``"claude-sonnet-4-6"``).
See :claude:`/model-config#model-aliases` for up-to-date model information.
effort : str, default ``"medium"``
Reasoning effort level (``"low"``, ``"medium"``, ``"high"``, ``"xhigh"``,
``"max"``). See :claude:`/model-config#choose-an-effort-level` for
supported effort levels for each model.
Attributes
----------
name : str
Name of the agent harness: ``"claude_code"``.
model : str
Model identifier this harness is configured to use.
effort : str
Reasoning effort level this harness is configured to use.
Examples
--------
Configure Claude Code agent harness with Claude Opus 4.7 and high effort::
>>> from milp_flare import FLARE
>>> from milp_flare.harness import ClaudeCodeHarness
>>> harness = ClaudeCodeHarness(model="claude-opus-4-7", effort="high")
>>> print(json.dumps(harness.get_config_dict(), indent=2))
{
"harness": "claude_code",
"image": "flare-agent:latest",
"model": "claude-opus-4-7",
"effort": "high"
}
"""
name = "claude_code"
def configure_wd(self, wd: Path) -> None:
super().configure_wd(wd)
# Copy MCP server configuration (passed to --mcp-config)
# https://code.claude.com/docs/en/mcp#project-scope
shutil.copy2(MCP_JSON, wd / ".mcp.json")
# Copy skills to .claude/skills
# https://code.claude.com/docs/en/skills#where-skills-live
claude_skills = wd / ".claude" / "skills"
claude_skills.parent.mkdir(exist_ok=True)
shutil.copytree(SKILLS_DIR, claude_skills, dirs_exist_ok=True)
def _agent_docker_args(self) -> list[str]:
# We use a long-lived token here instead of an API key to avoid the
# higher API costs compared a Claude Code subscription
# https://code.claude.com/docs/en/authentication#generate-a-long-lived-token
if "CLAUDE_CODE_OAUTH_TOKEN" not in os.environ:
raise RuntimeError(
"claude_code harness requires CLAUDE_CODE_OAUTH_TOKEN"
" from `claude setup-token`"
)
return ["-e", "CLAUDE_CODE_OAUTH_TOKEN"]
def _agent_command(self) -> str:
# Pass model and effort to the agent command template
return _TEMPLATE.replace("<<MODEL>>", self.model).replace(
"<<EFFORT>>", self.effort
)
def _parse_lines(self, lines: list[str]) -> dict[str, Any]:
"""Parse `claude -p --output-format stream-json` output."""
input_tokens = 0
output_tokens = 0
stop_reason: str | None = None
cost_usd: float | None = None
for line in lines:
line = line.strip()
if not line:
continue
try:
obj = json.loads(line)
except json.JSONDecodeError:
continue
if obj.get("type") == "result":
stop_reason = obj.get("stop_reason")
cost_usd = obj.get("total_cost_usd")
usage = obj.get("usage", {})
input_tokens = usage.get("input_tokens", input_tokens)
output_tokens = usage.get("output_tokens", output_tokens)
return {
"stop_reason": stop_reason,
"input_tokens": input_tokens,
"output_tokens": output_tokens,
"cost_usd": cost_usd,
}