Skip to content

Commit 194e975

Browse files
committed
release: merge develop into main for v0.14.1
2 parents 57d00f2 + db0d2d3 commit 194e975

31 files changed

Lines changed: 1609 additions & 100 deletions

.claude/agents/compass-planner.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ You produce **two artifacts** in Phase 2 of the canonical workflow (see `.claude
4646

4747
**Where to save:**
4848

49-
- **Feature-scoped work** (non-trivial, named feature): save both to `workspace/features/{feature-slug}/`
49+
- **Feature-scoped work** (non-trivial, named feature): save both to `workspace/development/features/{feature-slug}/`
5050
- `[C]prd-{feature}.md`
5151
- `[C]plan-{feature}.md`
5252
- **Standalone/one-off work** (no feature name, small scope): save to `workspace/development/plans/[C]plan-{name}-{YYYY-MM-DD}.md` and skip the PRD
@@ -63,9 +63,9 @@ Use the template at `.claude/templates/dev-work-plan.md` for the plan. The PRD s
6363
|---|---|---|---|
6464
| Typo, rename, tiny bug || ❌ (go direct to Bolt) ||
6565
| Small bug fix, clear repro || ✅ minimal | `workspace/development/plans/` |
66-
| Feature with clear acceptance criteria | ✅ (short) || `workspace/features/{slug}/` |
67-
| New feature with ambiguity | ✅ (full) || `workspace/features/{slug}/` |
68-
| High-stakes migration | ✅ (full) + RALPLAN-DR || `workspace/features/{slug}/` |
66+
| Feature with clear acceptance criteria | ✅ (short) || `workspace/development/features/{slug}/` |
67+
| New feature with ambiguity | ✅ (full) || `workspace/development/features/{slug}/` |
68+
| High-stakes migration | ✅ (full) + RALPLAN-DR || `workspace/development/features/{slug}/` |
6969

7070
**Rule:** when in doubt, produce a short PRD. A 10-line PRD is infinitely better than a missing one.
7171

@@ -115,13 +115,13 @@ Use the template at `.claude/templates/dev-work-plan.md` for the plan. The PRD s
115115

116116
1. Always read your memory folder first: `.claude/agent-memory/compass-planner/`
117117
2. Read `.claude/rules/dev-phases.md` — you are the owner of Phase 2 (Planning)
118-
3. Check for a feature folder: is there a `workspace/features/{slug}/` for this work? If yes, read any prior artifacts (discovery, etc.) to inherit context
118+
3. Check for a feature folder: is there a `workspace/development/features/{slug}/` for this work? If yes, read any prior artifacts (discovery, etc.) to inherit context
119119
4. Classify intent: Trivial / Refactoring / Build from Scratch / Mid-sized
120120
5. For codebase facts, spawn `@scout-explorer` (in parallel with other research)
121121
6. Ask user only about: priorities, timelines, scope decisions, risk tolerance, preferences
122122
7. For non-trivial work, consult `@echo-analyst` first for gap analysis
123123
8. Produce the PRD first (if applicable), then the plan derived from it
124-
9. Save to the feature folder (`workspace/features/{slug}/`) or `workspace/development/plans/` per the table above
124+
9. Save to the feature folder (`workspace/development/features/{slug}/`) or `workspace/development/plans/` per the table above
125125
10. Display confirmation summary, wait for explicit "proceed"
126126
11. On approval, hand off to `@apex-architect` (Phase 3) for non-trivial features, or directly to `@bolt-executor` (Phase 4) for clear executable plans
127127
12. Update agent memory with patterns worth remembering

.claude/agents/helm-conductor.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ Read `dev-phases.md` at the start of every session. Your recommendations must al
3737

3838
You don't have a dedicated working folder — you don't produce artifacts. You read from:
3939

40-
- `workspace/features/` — all active feature folders
40+
- `workspace/development/features/` — all active feature folders
4141
- `workspace/development/plans/` — standalone plans not yet in feature folders
4242
- `workspace/development/stories/` — story files (if present)
4343

44-
When you need to record a sequencing decision, append it to `workspace/features/{feature}/[C]helm-notes.md` in the relevant feature — short entries only.
44+
When you need to record a sequencing decision, append it to `workspace/development/features/{feature}/[C]helm-notes.md` in the relevant feature — short entries only.
4545

4646
## Identity
4747

@@ -51,7 +51,7 @@ When you need to record a sequencing decision, append it to `workspace/features/
5151

5252
## How you operate
5353

54-
1. **Read first, recommend second.** Before answering "what next", glob `workspace/features/*/` and read the most recent artifact in each (discovery, PRD, plan, verification, retro). You cannot sequence what you haven't seen.
54+
1. **Read first, recommend second.** Before answering "what next", glob `workspace/development/features/*/` and read the most recent artifact in each (discovery, PRD, plan, verification, retro). You cannot sequence what you haven't seen.
5555

5656
2. **Respect the 6 phases.** Every task belongs to a phase (Discovery, Planning, Solutioning, Build, Verify, Retro). Name the phase when you recommend.
5757

@@ -80,7 +80,7 @@ For the full rules, entry/exit criteria and skip conditions, read `.claude/rules
8080

8181
### "What should I work on next?"
8282

83-
1. Read all `workspace/features/*/` folders. For each, determine the current phase (look at which artifacts exist).
83+
1. Read all `workspace/development/features/*/` folders. For each, determine the current phase (look at which artifacts exist).
8484
2. For each feature, identify the next action (next phase or a blocker).
8585
3. Rank by: blockers first (to unblock), then by dependency order, then by priority signal from memory.
8686
4. Recommend the top 1-3 with phase + owner + why.
@@ -93,7 +93,7 @@ For the full rules, entry/exit criteria and skip conditions, read `.claude/rules
9393

9494
### "Sprint planning for {period}"
9595

96-
1. List candidate features (from `workspace/features/` or the user).
96+
1. List candidate features (from `workspace/development/features/` or the user).
9797
2. For each, identify which phases remain.
9898
3. Order by dependency.
9999
4. Propose a sequence: "Week 1: Feature A Phase 2-3, Feature B Phase 4. Week 2: Feature A Phase 4, Feature C Phase 1."

.claude/agents/mirror-retro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Beyond your own agent memory in `.claude/agent-memory/mirror-retro/`, you have *
3737

3838
Your workspace folder: the **feature folder itself**. You write retros next to the other artifacts:
3939

40-
- `workspace/features/{feature-slug}/[C]retro-{feature}-{YYYY-MM-DD}.md`
40+
- `workspace/development/features/{feature-slug}/[C]retro-{feature}-{YYYY-MM-DD}.md`
4141

4242
For sprint-level retros spanning multiple features:
4343

.claude/commands/helm-conductor.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Use the @helm-conductor agent to orchestrate the engineering cycle — sequence features, decide what to work on next, route tasks to the right specialist agent, or plan a sprint: $ARGUMENTS
22

3-
Helm is the conductor, not a worker. It reads the state of `workspace/features/`, understands the 6-phase workflow in `.claude/rules/dev-phases.md`, and recommends the next concrete action with owner agent, expected output, and blockers. If no arguments are provided, Helm should read the feature folders and recommend what to work on next.
3+
Helm is the conductor, not a worker. It reads the state of `workspace/development/features/`, understands the 6-phase workflow in `.claude/rules/dev-phases.md`, and recommends the next concrete action with owner agent, expected output, and blockers. If no arguments are provided, Helm should read the feature folders and recommend what to work on next.

.claude/rules/dev-phases.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Call `@helm-conductor` when you have multiple active features or are unsure whic
8484
Every non-trivial piece of work lives in its own feature folder:
8585

8686
```
87-
workspace/features/{feature-slug}/
87+
workspace/development/features/{feature-slug}/
8888
├── [C]discovery-{feature}.md ← Phase 1 (Echo)
8989
├── [C]prd-{feature}.md ← Phase 2 (Compass)
9090
├── [C]plan-{feature}.md ← Phase 2 (Compass)
@@ -110,7 +110,7 @@ workspace/features/{feature-slug}/
110110

111111
Before starting work, every engineering agent should check for prior artifacts in the active feature folder:
112112

113-
1. **Is there a feature folder for this work?** Look for `workspace/features/{slug}/`
113+
1. **Is there a feature folder for this work?** Look for `workspace/development/features/{slug}/`
114114
2. **If yes**, read in order: discovery → PRD → plan → architecture → any prior reviews/verifications
115115
3. **Inherit** constraints, decisions, and open questions — don't re-litigate them
116116
4. **If unclear** which feature this is, ask the user or call `@helm-conductor`
@@ -129,7 +129,7 @@ When one agent hands off to another, the handoff includes:
129129
- **Expected output:** what the next agent should produce and where
130130

131131
Example handoff:
132-
> "Compass → Bolt: plan saved to `workspace/features/dark-mode/[C]plan-dark-mode.md`. Architecture pending (Apex). Open question: token storage strategy (see plan §Open Questions). Expected: implementation against steps 1-5 + self-verification."
132+
> "Compass → Bolt: plan saved to `workspace/development/features/dark-mode/[C]plan-dark-mode.md`. Architecture pending (Apex). Open question: token storage strategy (see plan §Open Questions). Expected: implementation against steps 1-5 + self-verification."
133133
134134
---
135135

.env.example

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,32 @@
55
# Edit this file with your API keys.
66
# ============================================================
77

8+
# ── AI Provider Configuration ────────────────────────
9+
# EvoNexus supports multiple AI providers via OpenClaude.
10+
# Configure via dashboard (Providers page) or edit config/providers.json.
11+
# The active provider determines which CLI (claude or openclaude) is used.
12+
#
13+
# Anthropic (default): no extra config needed — uses native 'claude' CLI.
14+
#
15+
# OpenRouter (200+ models):
16+
# CLAUDE_CODE_USE_OPENAI=1
17+
# OPENAI_BASE_URL=https://openrouter.ai/api/v1
18+
# OPENAI_API_KEY=sk-or-...
19+
# OPENAI_MODEL=anthropic/claude-sonnet-4
20+
#
21+
# OpenAI:
22+
# CLAUDE_CODE_USE_OPENAI=1
23+
# OPENAI_API_KEY=sk-...
24+
# OPENAI_MODEL=gpt-4.1
25+
#
26+
# Google Gemini:
27+
# CLAUDE_CODE_USE_GEMINI=1
28+
# GEMINI_API_KEY=...
29+
# GEMINI_MODEL=gemini-2.5-pro
30+
#
31+
# Install openclaude for non-Anthropic providers:
32+
# npm install -g @gitlawb/openclaude
33+
834
# ── Omie ERP ─────────────────────────────────────────
935
# Omie API (omie.com.br → Settings → Integrations → API)
1036
OMIE_APP_KEY=

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ memory/**
3030
# ── Custom routines (user-specific, all in one place) ─
3131
ADWs/routines/custom/
3232

33+
# ── Provider config (user-specific, has API keys) ─
34+
config/providers.json
35+
3336
# ── Runtime data & logs ───────────────────
3437
backups/
3538
ADWs/logs/

ADWs/runner.py

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,37 +124,92 @@ def _log_to_file(log_name, prompt, stdout, stderr, returncode, duration, usage=N
124124
f.write(f"{'='*60}\nSTDERR:\n{'='*60}\n{stderr}\n")
125125

126126

127+
_ALLOWED_CLI_COMMANDS = frozenset({"claude", "openclaude"})
128+
129+
130+
def _spawn_cli(cli_command: str, prompt: str, agent: str | None, provider_env: dict) -> subprocess.Popen:
131+
"""Spawn a CLI process using only hardcoded command strings.
132+
133+
Uses a dictionary lookup so that the subprocess argument is always
134+
a static string, satisfying semgrep/opengrep subprocess injection rules.
135+
"""
136+
base_args = ["--print", "--dangerously-skip-permissions", "--output-format", "json"]
137+
if agent:
138+
base_args.extend(["--agent", agent])
139+
base_args.append(prompt)
140+
141+
env = {**os.environ, **provider_env, "TERM": "dumb"}
142+
popen_kwargs = dict(
143+
stdout=subprocess.PIPE,
144+
stderr=subprocess.PIPE,
145+
text=True,
146+
cwd=str(WORKSPACE),
147+
env=env,
148+
)
149+
150+
# Hardcoded dispatch — each branch uses a literal string for the executable
151+
if cli_command == "openclaude":
152+
return subprocess.Popen(["openclaude"] + base_args, **popen_kwargs) # noqa: S603
153+
else:
154+
return subprocess.Popen(["claude"] + base_args, **popen_kwargs) # noqa: S603
155+
_ALLOWED_ENV_VARS = frozenset({
156+
"CLAUDE_CODE_USE_OPENAI", "CLAUDE_CODE_USE_GEMINI", "CLAUDE_CODE_USE_BEDROCK",
157+
"CLAUDE_CODE_USE_VERTEX", "OPENAI_BASE_URL", "OPENAI_API_KEY", "OPENAI_MODEL",
158+
"GEMINI_API_KEY", "GEMINI_MODEL", "AWS_REGION", "AWS_BEARER_TOKEN_BEDROCK",
159+
"ANTHROPIC_VERTEX_PROJECT_ID", "CLOUD_ML_REGION",
160+
})
161+
162+
163+
def _get_provider_config() -> tuple[str, dict]:
164+
"""Read active provider CLI command and env vars from config/providers.json.
165+
166+
Only allowlisted CLI commands and env var names are returned.
167+
"""
168+
config_path = WORKSPACE / "config" / "providers.json"
169+
if not config_path.is_file():
170+
return "claude", {}
171+
try:
172+
config = json.loads(config_path.read_text(encoding="utf-8"))
173+
active = config.get("active_provider", "anthropic")
174+
provider = config.get("providers", {}).get(active, {})
175+
cli = provider.get("cli_command", "claude")
176+
if cli not in _ALLOWED_CLI_COMMANDS:
177+
cli = "claude"
178+
env_vars = {
179+
k: v for k, v in provider.get("env_vars", {}).items()
180+
if v and k in _ALLOWED_ENV_VARS
181+
}
182+
return cli, env_vars
183+
except (json.JSONDecodeError, OSError):
184+
return "claude", {}
185+
186+
127187
def run_claude(prompt: str, log_name: str = "unnamed", timeout: int = 600, agent: str = None) -> dict:
128188
"""
129-
Execute Claude Code CLI with streaming output.
189+
Execute AI CLI (claude or openclaude) with streaming output.
190+
191+
Uses the active provider from config/providers.json to determine
192+
which binary to run and which env vars to inject.
130193
131194
Args:
132195
prompt: The prompt to execute
133196
log_name: Name for logs
134197
timeout: Timeout in seconds
135198
agent: Agent name (.claude/agents/*.md) — if None, runs without agent
136199
"""
137-
cmd = ["claude", "--print", "--dangerously-skip-permissions", "--output-format", "json"]
200+
cli_command, provider_env = _get_provider_config()
138201

139202
if agent:
140-
cmd.extend(["--agent", agent])
141-
142-
cmd.append(prompt)
143-
144-
agent_label = f"@{agent}" if agent else ""
145-
console.print(f" [step]▶[/step] {log_name} [dim]{agent_label}[/dim]", end="")
203+
agent_label = f"@{agent}"
204+
else:
205+
agent_label = ""
206+
provider_label = f"[{cli_command}]" if cli_command != "claude" else ""
207+
console.print(f" [step]▶[/step] {log_name} [dim]{agent_label} {provider_label}[/dim]", end="")
146208

147209
start_time = datetime.now()
148210

149211
try:
150-
process = subprocess.Popen(
151-
cmd,
152-
stdout=subprocess.PIPE,
153-
stderr=subprocess.PIPE,
154-
text=True,
155-
cwd=str(WORKSPACE),
156-
env={**os.environ, "TERM": "dumb"},
157-
)
212+
process = _spawn_cli(cli_command, prompt, agent, provider_env)
158213

159214
stdout_lines = []
160215
line_count = 0

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.14.1] - 2026-04-11
9+
10+
### Fixed
11+
12+
- **`/api/overview` endpoint** — dropped from ~16s to ~29ms (≈500× faster). `_recent_reports` was rglob'ing the entire `workspace/` tree, which on an active install holds vendored third-party repos under `workspace/projects/` (mcp-dev-brasil, oh-my-claudecode, evoai-services, etc.) — 16.853 of 17.116 MD/HTML files (98.5%) lived there and had nothing to do with "recent reports". The scan now skips top-level `projects/` (vendored repos) and `meetings/` (raw Fathom transcripts), iterates remaining areas, and formats the `date` field from the actual `mtime` instead of `path.split("/")[-1][:10]` (which was returning garbage like `"README.md"`).
13+
- **Site typecheck errors**`site/src/pages/Home.tsx` had 3 lucide icons (`MessageSquare`, `GitBranch`, `Database`) passing an invalid `title` prop. Wrapped them in `<span title="...">` to keep the hover tooltip and pass `tsc --noEmit`.
14+
- **Dashboard frontend build**`dashboard/frontend/src/pages/Providers.tsx` was importing `type LucideIcon` without using it, which caused `make dashboard-app` to fail with `TS6133`. Unused import removed.
15+
- **Terminal startup garbage (WIP, 2 attempts included)** — on starting any agent terminal from the dashboard, bytes like `0?1;2c` / `000000` / `^[[0^[[0...` showed up in the prompt and status bar. Root cause is xterm.js auto-replying to terminal queries (DA1 `\x1b[c`, DA2 `\x1b[>c`, DSR `\x1b[5n`/`\x1b[6n`, window ops `\x1b[...t`) via `term.onData`, which the frontend was forwarding to the pty as if it were keyboard input. This release ships two defensive layers — passing `cols`/`rows` upfront on `start_claude` so the pty is born at the right size, and registering CSI handlers via `term.parser.registerCsiHandler({ final: 'c' | 'n' | 't' }, () => true)` to intercept queries at the parser level — plus a regex filter on `onData` as a second line of defense. **The bug is not fully resolved in this release.** Some payloads still slip through (likely via a non-CSI `triggerDataEvent` path that hasn't been pinned down yet). A debug log was added to `AgentTerminal.tsx` to capture the exact bytes in the next iteration.
16+
17+
### Changed
18+
19+
- **Feature folder convention**`workspace/features/{slug}/` is now `workspace/development/features/{slug}/` across all engineering layer prompts (`.claude/rules/dev-phases.md`, `.claude/agents/compass-planner.md`, `.claude/agents/helm-conductor.md`, `.claude/commands/helm-conductor.md`, `.claude/agents/mirror-retro.md`, `docs/agents/engineering-layer.md`). Keeps all engineering artifacts (features, plans, architecture, reviews, verifications, retros) grouped under one development/ root.
20+
21+
### Docs
22+
23+
- **Multi-provider documentation** — README, `docs/introduction.md`, `docs/getting-started.md`, `docs/reference/env-variables.md`, `docs/dashboard/overview.md` updated with the OpenClaude-based multi-provider story introduced in v0.14.0. New `docs/dashboard/providers.md` documents the Providers page (supported providers, activation flow, security model with CLI + env var allowlists, logout warning). Site landing page replaces the "Full Control" feature card with "Multi-Provider, No Lock-In" highlighting the new capability.
24+
825
## [0.14.0] - 2026-04-10
926

1027
### Added

0 commit comments

Comments
 (0)