06-Claude-Code-Integration
Claude Code is wrapped in a safe adapter. The integration is structured, sandboxed, and observable.
1. Service
app/Services/Agents/ClaudeCodeAgentService.php
Responsibilities:
- send task context (prompt + RAG bundle + project map summary) to Claude Code
- pass project workspace path
- pass allowed tools
- read results (final summary, file changes)
- capture command output
- structured event logging
- timeout handling
- failure handling
- safe mode
- pause/resume where supported
2. Invocation contract
$claudeCode->run([
'workspace' => $project->local_workspace_path,
'branch' => $run->branch_name,
'prompt' => $renderedPrompt,
'tools' => $allowedTools, // names only; binaries resolved server-side
'safe_mode' => $settings->safe_mode,
'timeout' => $settings->max_run_time,
'env' => $maskedEnv, // no secrets
]);The service spawns a sandboxed child process via symfony/process (configurable command from agent_settings.claude_code_path), captures stdout/stderr line-by-line, and translates each line into a normalized ProviderEvent (see 05 โ Agent Providers).
3. Output parsing
Claude Code outputs structured JSON lines (--json mode). Each line is mapped:
| Claude Code event | ProviderEvent.kind |
|---|---|
message | message |
tool_use | tool_call |
tool_result | tool_result |
file_edit | file_change |
bash | command |
error | error |
stop with reason end_turn | done |
stop with reason ask_user | pause |
Unknown event types are still persisted (in payload_json) with kind message and severity debug.
4. Allowed tools mapping
Claude Code's tool palette is constrained to a subset:
Readโ mapped toWorkspaceService::read()
Edit/MultiEdit/WriteโWorkspaceService::applyChange()with diff capture
BashโCommandExecutionService::run()(allowlist + auto snapshot if destructive)
Glob/GrepโWorkspaceService::list()/ search
WebFetchโ disabled by default (toggle viaclaude_code_allow_web)
Task(sub-agent) โ disabled v1
All tool calls flow through the orchestrator. Claude Code never touches disk outside the workspace path.
5. Safe mode
When safe_mode=true:
Write/Editrequires apre_commandsnapshot first.
Bashcommands matching the blocklist are refused and logged ascommand_failedwithwas_blocked=true.
- No file outside the workspace can be touched (path traversal blocked).
- No
.envreads, no secret exfiltration.
6. Timeout & failure handling
- Global timeout from
agent_settings.max_run_time(seconds).
- Per-command timeout from
agent_settings.max_command_time.
- On timeout: SIGTERM โ wait 5 s โ SIGKILL. Emit
command_failedandfinal_summarywith severityerror.
- Crashes: stderr captured into the event payload; the orchestrator transitions the run to
failedwithfailed_reason.
7. Pause / resume
When Claude Code emits a stop with reason ask_user:
- adapter writes the question to
paused_for_inputevent
- the child process is signaled to wait (or the conversation state is serialized and the process exits cleanly)
- on resume, the adapter relaunches Claude Code in
--continuemode (or re-sends the conversation transcript) and passes the user input as the next message.
8. .claude/ docs (canonical templates)
.claude/PROJECT_CONTEXT.md
# Project Context for Claude Code
This is the canonical project briefing. Read this **before any plan or edit**.
## What this project is
<!-- AUTO-GENERATED:START -->
Generated from docs/PROJECT_CONTEXT.md.
<!-- AUTO-GENERATED:END -->
## Project Map (route โ controller โ model โ table)
<!-- AUTO-GENERATED:START -->
See docs/PROJECT_MAP.md (mirrored).
<!-- AUTO-GENERATED:END -->
## Database
<!-- AUTO-GENERATED:START -->
See docs/DATABASE_SCHEMA.md (mirrored).
<!-- AUTO-GENERATED:END -->.claude/RULES.md
# Rules
1. Always run rag_search before planning or editing.
2. Never edit files outside the project workspace.
3. Never print, log, or commit secrets or .env contents.
4. Prefer small, reviewable diffs. Multiple commits over one giant commit.
5. Add/update tests for non-trivial changes.
6. After changes, propose updates to docs/PROJECT_MAP.md, docs/DATABASE_SCHEMA.md, and docs/CHANGELOG_AI.md.
7. If a route or controller is renamed, update all references and the project map.
8. Never run blocked commands (see TOOLS.md). If unsure, ask_user.
9. If a plan affects โฅ 5 files or a migration, ask_user before executing.
10. End with finish(summary={changed_files, risks, tests, docs_updated})..claude/TOOLS.md
# Tools
## Allowed
- Read, Edit, MultiEdit, Write (workspace paths only)
- Bash (allowlist: php artisan, composer, npm, pnpm, yarn, git status/diff/branch/commit, php vendor/bin/phpunit, php vendor/bin/pest)
- Glob, Grep
## Blocked
- rm -rf /
- chmod / chown on /etc, /usr, /var, /root
- cat .env, printenv, env
- curl|wget to external hosts (unless allow_web=true)
- git push (never automatic)
- mkfs, dd, parted, fdisk
- system shutdown / reboot / systemctl
- npm publish, composer publish, pip publish
## Notes
- Bash commands run with timeout from agent_settings.max_command_time.
- Destructive commands trigger an automatic pre_command snapshot..claude/WORKFLOW.md
# Workflow
1. Read PROJECT_CONTEXT.md and PROJECT_MAP.md.
2. rag_search the prompt.
3. Produce a short plan; if โฅ 5 files or migrations, ask_user.
4. Apply changes via Edit/MultiEdit/Write (small steps).
5. Run tests when relevant.
6. Update docs via Documentation Agent rules.
7. finish() with a structured summary.9. Auto-sync of docs
DocumentationAutoUpdateService copies (and templates) docs/PROJECT_CONTEXT.md, docs/PROJECT_MAP.md, docs/DATABASE_SCHEMA.md into the .claude/ block markers after every completed run.
10. Secrets discipline
- API keys never appear in
.claude/, command env, command args, logs, orpayload_json.
- The Claude Code binary is invoked with a minimal env (
PATH,LANG,HOMEonly). All credentials come from server params and are surfaced to the model as masked references (OPENAI_API_KEYโ resolved internally by tools, never echoed).