Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/backend/core/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,14 @@ def get_sdk_env_vars() -> dict[str, str]:
if bash_path:
env["CLAUDE_CODE_GIT_BASH_PATH"] = bash_path

# Explicitly unset CLAUDECODE in SDK subprocess environment.
#
# Claude Code CLI refuses to start when this marker env var is present,
# treating it as a nested Claude Code session. Auto-Claude can run inside
# a Claude Code terminal during debugging, so we must clear this marker for
# child SDK/CLI processes.
env["CLAUDECODE"] = ""

# Explicitly unset PYTHONPATH in SDK subprocess environment to prevent
# pollution of agent subprocess environments. This fixes ACS-251 where
# external projects with different Python versions would fail due to
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import os
import threading
import time
from collections.abc import Callable
from pathlib import Path
from typing import Any

Expand Down Expand Up @@ -536,6 +537,7 @@ def create_client(
betas: list[str] | None = None,
effort_level: str | None = None,
fast_mode: bool = False,
stderr_callback: Callable[[str], None] | None = None,
) -> ClaudeSDKClient:
"""
Create a Claude Agent SDK client with multi-layered security.
Expand Down Expand Up @@ -571,6 +573,8 @@ def create_client(
the "user" setting source so the CLI reads fastMode from
~/.claude/settings.json. Requires extra usage enabled on Claude
subscription; falls back to standard speed automatically.
stderr_callback: Optional callback invoked with each stderr line emitted
by the Claude CLI process.

Returns:
Configured ClaudeSDKClient
Expand Down Expand Up @@ -959,6 +963,9 @@ def create_client(
"enable_file_checkpointing": True,
}

if stderr_callback:
options_kwargs["stderr"] = stderr_callback

# Fast mode: enable user setting source so CLI reads fastMode from
# ~/.claude/settings.json. Without this, the SDK's default --setting-sources ""
# blocks all filesystem settings and the CLI never sees fastMode: true.
Expand Down
72 changes: 41 additions & 31 deletions apps/backend/prompts/spec_quick.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,46 +31,46 @@ That's it. No deep analysis needed.

## PHASE 2: CREATE MINIMAL SPEC

Create a concise `spec.md`:
Create a concise `spec.md` that includes the required validator sections:

```bash
cat > spec.md << 'EOF'
# Quick Spec: [Task Name]
# Specification: [Task Name]

## Task
[One sentence description]
## Overview
[One paragraph describing what is being changed and why]

## Files to Modify
## Workflow Type
**Type**: simple

## Task Scope
### Files to Modify
- `[path/to/file]` - [what to change]

## Change Details
### Change Details
[Brief description of the change - a few sentences max]

## Verification
## Success Criteria
- [ ] [How to verify the change works]

## Notes
[Any gotchas or considerations - optional]
EOF
```

**Keep it short!** A simple spec should be 20-50 lines, not 200+.
**Keep it short!** A simple spec should be concise and focused.

---

## PHASE 3: CREATE SIMPLE PLAN

Create `implementation_plan.json`:
Create `implementation_plan.json` with current schema fields:

```bash
cat > implementation_plan.json << 'EOF'
{
"spec_name": "[spec-name]",
"feature": "[task description]",
"workflow_type": "simple",
"total_phases": 1,
"recommended_workers": 1,
"phases": [
{
"id": "phase-1",
"phase": 1,
"name": "Implementation",
"description": "[task description]",
Expand All @@ -86,17 +86,19 @@ cat > implementation_plan.json << 'EOF'
"patterns_from": [],
"verification": {
"type": "manual",
"run": "[verification step]"
"instructions": "[verification step]"
}
}
]
}
],
"metadata": {
"created_at": "[timestamp]",
"complexity": "simple",
"estimated_sessions": 1
}
"summary": {
"total_phases": 1,
"total_subtasks": 1,
"recommended_workers": 1
},
"created_at": "[timestamp]",
"updated_at": "[timestamp]"
}
EOF
```
Expand Down Expand Up @@ -146,18 +148,22 @@ Ready for implementation.

**spec.md**:
```markdown
# Quick Spec: Button Color Change
# Specification: Button Color Change

## Task
## Overview
Update primary button color from blue (#3B82F6) to green (#22C55E).

## Files to Modify
## Workflow Type
**Type**: simple

## Task Scope
### Files to Modify
- `src/components/Button.tsx` - Update color constant

## Change Details
### Change Details
Change the `primaryColor` variable from `#3B82F6` to `#22C55E`.

## Verification
## Success Criteria
- [ ] Buttons appear green in the UI
- [ ] No console errors
```
Expand All @@ -168,18 +174,22 @@ Change the `primaryColor` variable from `#3B82F6` to `#22C55E`.

**spec.md**:
```markdown
# Quick Spec: Fix Welcome Typo
# Specification: Fix Welcome Typo

## Task
## Overview
Correct spelling of "recieve" to "receive" in welcome message.

## Files to Modify
## Workflow Type
**Type**: simple

## Task Scope
### Files to Modify
- `src/pages/Home.tsx` - Fix typo on line 42

## Change Details
### Change Details
Find "You will recieve" and change to "You will receive".

## Verification
## Success Criteria
- [ ] Welcome message displays correctly
```

Expand Down
52 changes: 45 additions & 7 deletions apps/backend/spec/phases/spec_phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,16 @@ async def phase_quick_spec(self) -> PhaseResult:
plan_file = self.spec_dir / "implementation_plan.json"

if spec_file.exists() and plan_file.exists():
self.ui.print_status("Quick spec already exists", "success")
return PhaseResult(
"quick_spec", True, [str(spec_file), str(plan_file)], [], 0
spec_valid = self.spec_validator.validate_spec_document().valid
plan_valid = self.spec_validator.validate_implementation_plan().valid
if spec_valid and plan_valid:
self.ui.print_status("Quick spec already exists", "success")
return PhaseResult(
"quick_spec", True, [str(spec_file), str(plan_file)], [], 0
)

self.ui.print_status(
"Quick spec files exist but are invalid, regenerating...", "warning"
)

is_greenfield = self._check_and_log_greenfield()
Expand Down Expand Up @@ -91,15 +98,46 @@ async def phase_quick_spec(self) -> PhaseResult:
phase_name="quick_spec",
)

if success and spec_file.exists():
if success:
# Create minimal plan if agent didn't
if not plan_file.exists():
writer.create_minimal_plan(self.spec_dir, self.task_description)

self.ui.print_status("Quick spec created", "success")
return PhaseResult(
"quick_spec", True, [str(spec_file), str(plan_file)], [], attempt
spec_valid = (
spec_file.exists()
and self.spec_validator.validate_spec_document().valid
)
plan_valid = (
plan_file.exists()
and self.spec_validator.validate_implementation_plan().valid
)

if not plan_valid and plan_file.exists():
from ..validate_pkg.auto_fix import auto_fix_plan

if auto_fix_plan(self.spec_dir):
plan_valid = (
self.spec_validator.validate_implementation_plan().valid
)

if spec_valid and plan_valid:
self.ui.print_status("Quick spec created", "success")
return PhaseResult(
"quick_spec",
True,
[str(spec_file), str(plan_file)],
[],
attempt,
)

errors.append(
f"Attempt {attempt + 1}: Quick spec output invalid "
f"(spec_valid={spec_valid}, plan_valid={plan_valid})"
)
self.ui.print_status(
"Quick spec created files but validation failed", "error"
)
continue

errors.append(f"Attempt {attempt + 1}: Quick spec agent failed")

Expand Down
Loading
Loading