devcouncil 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +190 -6
- package/package.json +9 -2
- package/pyproject.toml +34 -2
- package/src/devcouncil/app/config.py +167 -5
- package/src/devcouncil/artifacts/graph.py +23 -3
- package/src/devcouncil/assets/__init__.py +1 -0
- package/src/devcouncil/assets/devcouncil-logo.svg +60 -0
- package/src/devcouncil/assets/devcouncil_logo_premium.png +0 -0
- package/src/devcouncil/cli/commands/agents.py +292 -0
- package/src/devcouncil/cli/commands/artifacts.py +6 -3
- package/src/devcouncil/cli/commands/check.py +209 -0
- package/src/devcouncil/cli/commands/config.py +43 -4
- package/src/devcouncil/cli/commands/cost.py +57 -0
- package/src/devcouncil/cli/commands/dashboard.py +6 -1
- package/src/devcouncil/cli/commands/doctor.py +221 -21
- package/src/devcouncil/cli/commands/evidence.py +48 -0
- package/src/devcouncil/cli/commands/go.py +452 -33
- package/src/devcouncil/cli/commands/handoff.py +69 -0
- package/src/devcouncil/cli/commands/hook.py +124 -15
- package/src/devcouncil/cli/commands/init.py +154 -18
- package/src/devcouncil/cli/commands/integrate.py +894 -105
- package/src/devcouncil/cli/commands/map.py +80 -10
- package/src/devcouncil/cli/commands/plan.py +212 -51
- package/src/devcouncil/cli/commands/prompt.py +18 -7
- package/src/devcouncil/cli/commands/repair.py +40 -23
- package/src/devcouncil/cli/commands/report.py +8 -0
- package/src/devcouncil/cli/commands/reset_demo_state.py +4 -2
- package/src/devcouncil/cli/commands/rollback.py +27 -28
- package/src/devcouncil/cli/commands/run.py +69 -49
- package/src/devcouncil/cli/commands/runs.py +223 -0
- package/src/devcouncil/cli/commands/scaffold.py +32 -0
- package/src/devcouncil/cli/commands/semantic.py +47 -0
- package/src/devcouncil/cli/commands/setup.py +145 -6
- package/src/devcouncil/cli/commands/shell.py +73 -0
- package/src/devcouncil/cli/commands/skills.py +88 -0
- package/src/devcouncil/cli/commands/status.py +25 -1
- package/src/devcouncil/cli/commands/trace.py +47 -3
- package/src/devcouncil/cli/commands/verify.py +138 -3
- package/src/devcouncil/cli/commands/watch.py +9 -9
- package/src/devcouncil/cli/commands/watch_fs.py +40 -0
- package/src/devcouncil/cli/main.py +56 -7
- package/src/devcouncil/domain/evidence.py +22 -2
- package/src/devcouncil/domain/gap.py +27 -1
- package/src/devcouncil/domain/task.py +31 -2
- package/src/devcouncil/execution/checkpoints.py +246 -0
- package/src/devcouncil/execution/context_builder.py +1 -1
- package/src/devcouncil/execution/fs_watcher.py +180 -0
- package/src/devcouncil/execution/handoff.py +102 -0
- package/src/devcouncil/execution/hook_policy.py +162 -74
- package/src/devcouncil/execution/patch.py +59 -10
- package/src/devcouncil/execution/permissions.py +17 -24
- package/src/devcouncil/execution/policy_engine.py +343 -0
- package/src/devcouncil/execution/prompt_builder.py +633 -21
- package/src/devcouncil/execution/shell_session.py +225 -0
- package/src/devcouncil/execution/task_runner.py +6 -2
- package/src/devcouncil/executors/agent_registry.py +575 -0
- package/src/devcouncil/executors/coding_cli.py +663 -39
- package/src/devcouncil/executors/native/agent.py +121 -20
- package/src/devcouncil/gating/checks/clean_git.py +3 -1
- package/src/devcouncil/gating/checks/secret_scan_check.py +40 -21
- package/src/devcouncil/gating/policy.py +158 -10
- package/src/devcouncil/hardware.py +184 -0
- package/src/devcouncil/indexing/ast_matcher.py +1 -1
- package/src/devcouncil/indexing/lsp.py +45 -4
- package/src/devcouncil/indexing/repo_mapper.py +1256 -9
- package/src/devcouncil/indexing/semantic_index.py +205 -0
- package/src/devcouncil/integrations/actions.py +146 -0
- package/src/devcouncil/integrations/check.py +423 -0
- package/src/devcouncil/integrations/github_intent.py +142 -0
- package/src/devcouncil/integrations/gitnexus.py +35 -0
- package/src/devcouncil/integrations/mcp/server.py +1552 -29
- package/src/devcouncil/integrations/opencode_devcouncil_plugin.mjs +24 -0
- package/src/devcouncil/live/cards.py +161 -19
- package/src/devcouncil/live/signals.py +2 -2
- package/src/devcouncil/live/transcripts.py +9 -6
- package/src/devcouncil/llm/cache.py +10 -6
- package/src/devcouncil/llm/model_defaults.yaml +44 -0
- package/src/devcouncil/llm/provider.py +515 -34
- package/src/devcouncil/llm/router.py +231 -46
- package/src/devcouncil/optimization/__init__.py +1 -0
- package/src/devcouncil/optimization/gepa_agent.py +318 -0
- package/src/devcouncil/planning/correction_manifest.py +303 -0
- package/src/devcouncil/planning/critique_service.py +7 -2
- package/src/devcouncil/planning/plan_service.py +17 -3
- package/src/devcouncil/planning/prompt_enhancer_service.py +82 -1
- package/src/devcouncil/planning/spec_service.py +27 -1
- package/src/devcouncil/repo/ci_scaffold.py +157 -0
- package/src/devcouncil/repo/gitignore.py +123 -0
- package/src/devcouncil/repo/sca.py +374 -0
- package/src/devcouncil/reporting/json_report.py +11 -1
- package/src/devcouncil/reporting/markdown_report.py +15 -0
- package/src/devcouncil/skills/__init__.py +19 -0
- package/src/devcouncil/skills/library/README.md +46 -0
- package/src/devcouncil/skills/library/ai-training.md +50 -0
- package/src/devcouncil/skills/library/android.md +50 -0
- package/src/devcouncil/skills/library/backend.md +52 -0
- package/src/devcouncil/skills/library/core-engineering.md +95 -0
- package/src/devcouncil/skills/library/data-engineering.md +47 -0
- package/src/devcouncil/skills/library/desktop.md +46 -0
- package/src/devcouncil/skills/library/devops.md +48 -0
- package/src/devcouncil/skills/library/game-dev.md +46 -0
- package/src/devcouncil/skills/library/ios.md +48 -0
- package/src/devcouncil/skills/library/mobile-cross-platform.md +46 -0
- package/src/devcouncil/skills/library/security.md +48 -0
- package/src/devcouncil/skills/library/systems.md +48 -0
- package/src/devcouncil/skills/library/web.md +47 -0
- package/src/devcouncil/skills/library/windows.md +47 -0
- package/src/devcouncil/skills/registry.py +330 -0
- package/src/devcouncil/storage/db.py +83 -2
- package/src/devcouncil/storage/models.py +121 -0
- package/src/devcouncil/storage/native.py +557 -0
- package/src/devcouncil/storage/repositories.py +137 -75
- package/src/devcouncil/telemetry/cost.py +123 -17
- package/src/devcouncil/telemetry/model_pricing.yaml +48 -0
- package/src/devcouncil/telemetry/pricing.py +28 -0
- package/src/devcouncil/telemetry/traces.py +62 -7
- package/src/devcouncil/telemetry/tracker.py +12 -9
- package/src/devcouncil/ui/dashboard.py +324 -23
- package/src/devcouncil/utils/redaction.py +9 -3
- package/src/devcouncil/utils/subprocess_env.py +69 -0
- package/src/devcouncil/verification/acceptance_compiler.py +125 -0
- package/src/devcouncil/verification/ad_hoc_check.py +129 -0
- package/src/devcouncil/verification/diff_coverage.py +353 -0
- package/src/devcouncil/verification/next_actions.py +189 -0
- package/src/devcouncil/verification/sandbox.py +178 -0
- package/src/devcouncil/verification/test_resolver.py +91 -0
- package/src/devcouncil/verification/verifier.py +1065 -47
- package/uv.lock +205 -64
- package/src/devcouncil/indexing/symbol_index.py +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# DevCouncil: The Gated AI Orchestrator
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/bharathvbcr/DevCouncil/main/src/devcouncil/assets/devcouncil_logo_premium.png" alt="DevCouncil Logo" width="300">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
3
7
|
[](LICENSE)
|
|
4
8
|
[](https://www.python.org/downloads/)
|
|
5
9
|
[](https://github.com/astral-sh/uv)
|
|
@@ -8,16 +12,19 @@
|
|
|
8
12
|
|
|
9
13
|
DevCouncil is a high-integrity command-line orchestration platform for AI-assisted software development. It turns AI implementation from a black-box generation task into a gated engineering workflow where every change is authorized, verified, and traceable back to a requirement.
|
|
10
14
|
|
|
11
|
-
DevCouncil does not replace coding agents. It sits beside tools like Codex CLI, Gemini CLI, Claude Code, Cursor, and
|
|
15
|
+
DevCouncil does not replace coding agents. It sits beside tools like Codex CLI, Gemini CLI, Claude Code, OpenCode, Google Antigravity CLI, Warp/Oz, Cursor, Aider, and bring-your-own prompt-taking CLIs, then owns the plan, task scope, verification loop, repair prompts, and evidence trail.
|
|
12
16
|
|
|
13
17
|
## Documentation
|
|
14
18
|
|
|
15
19
|
- [Quickstart](docs/quickstart.md): shortest install-to-first-task path.
|
|
16
20
|
- [Daily workflow](docs/workflow.md): manual sidecar loop, verification, repair, and rollback.
|
|
17
|
-
- [Coding CLI integration](docs/coding-cli-integration.md): Codex, Gemini, Claude Code, Cursor, Aider, MCP, hooks, and automated executors.
|
|
21
|
+
- [Coding CLI integration](docs/coding-cli-integration.md): Codex, Gemini, Claude Code, OpenCode, Antigravity, Cursor, Aider, MCP, hooks, and automated executors.
|
|
22
|
+
- [Integration tiers](docs/integration-tiers.md): headless executor vs MCP-only vs sidecar definitions.
|
|
18
23
|
- [CLI command reference](docs/cli-reference.md): available `dev` commands.
|
|
19
24
|
- [Architecture](docs/architecture.md): components, artifact graph, state machine, and gated execution.
|
|
25
|
+
- [Executor adapters](docs/executor-adapters.md): manual, coding CLI, native-preview, Mini-SWE, and OpenHands execution paths.
|
|
20
26
|
- [Live review](docs/live-review.md): `dev watch` session review, cards, signals, and blocking behavior.
|
|
27
|
+
- [Model routing](docs/model-routing.md): provider selection, role models, OpenRouter, Vertex AI, Doubleword, and Ollama (local) setup.
|
|
21
28
|
- [Security model](docs/security.md): redaction, permissions, allowlists, and local state.
|
|
22
29
|
- [Project status](docs/project-status.md): current maturity by subsystem.
|
|
23
30
|
- [Roadmap](docs/roadmap.md): planned work.
|
|
@@ -73,12 +80,27 @@ dev verify TASK-001
|
|
|
73
80
|
|
|
74
81
|
On a fresh interactive setup, DevCouncil can configure supported coding CLI integrations immediately; pass `--skip-integrations` if you want to defer that step.
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
### Run locally on macOS (Apple Silicon + Ollama)
|
|
84
|
+
|
|
85
|
+
DevCouncil runs fully offline against [Ollama](https://ollama.com) — no API key, no per-token cost. It is Apple-Silicon-aware: `dev setup --provider ollama` sizes the default local model to your Mac's unified memory, and `dev doctor` reports the chip/RAM, pings the Ollama server, and flags a too-small context window.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
brew install ollama && ollama serve
|
|
89
|
+
ollama pull qwen2.5-coder:32b # use the size `dev doctor` recommends for your RAM
|
|
90
|
+
export OLLAMA_NUM_CTX=16384 # large planning prompts need a raised context window
|
|
91
|
+
dev setup --provider ollama # auto-selects the model for your RAM
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See [Model routing → macOS / Apple Silicon](docs/model-routing.md) for the RAM-to-model table.
|
|
95
|
+
|
|
96
|
+
Paste only the output from `dev prompt TASK-001` into Codex, Gemini, Claude Code, OpenCode, Antigravity, Warp, Cursor, Aider, or another coding tool. Keep `dev setup`, `dev plan`, `dev run`, and `dev verify` in the terminal at the repository root.
|
|
77
97
|
|
|
78
98
|
For an automated end-to-end run with a supported coding CLI installed:
|
|
79
99
|
|
|
80
100
|
```bash
|
|
81
101
|
dev e2e "Describe the implementation goal" --executor codex
|
|
102
|
+
dev e2e "Describe the implementation goal" --executor antigravity
|
|
103
|
+
dev e2e "Describe the implementation goal" --executor warp
|
|
82
104
|
dev go "Describe the implementation goal" --executor codex
|
|
83
105
|
```
|
|
84
106
|
|
|
@@ -87,14 +109,132 @@ dev go "Describe the implementation goal" --executor codex
|
|
|
87
109
|
For machine-readable agent handoff, write the final report to a stable file:
|
|
88
110
|
|
|
89
111
|
```bash
|
|
90
|
-
dev e2e "Describe the implementation goal" --agent
|
|
91
|
-
dev e2e "Describe the implementation goal" --json --report-file .devcouncil/reports/latest.json
|
|
112
|
+
dev e2e "Describe the implementation goal" --executor codex --agent
|
|
113
|
+
dev e2e "Describe the implementation goal" --executor codex --json --report-file .devcouncil/reports/latest.json
|
|
92
114
|
```
|
|
93
115
|
|
|
94
|
-
`--agent`
|
|
116
|
+
`--agent` enables JSON output and writes `.devcouncil/reports/latest.json`. Fresh projects default to manual sidecar mode, so pass an automated executor or set `execution.default_executor` before using `dev e2e` without `--executor`.
|
|
95
117
|
|
|
96
118
|
See the full [quickstart](docs/quickstart.md) for installation variants, API-key setup, and first-run guidance.
|
|
97
119
|
|
|
120
|
+
OpenCode and Google Antigravity CLI are built-in executors and MCP integrations:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
dev integrate opencode --apply
|
|
124
|
+
dev run TASK-001 --executor opencode
|
|
125
|
+
dev agents run TASK-001 --agent opencode --profile default
|
|
126
|
+
dev integrate antigravity --apply
|
|
127
|
+
dev run TASK-001 --executor antigravity
|
|
128
|
+
dev agents run TASK-001 --agent agy --profile default
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Register any other local CLI that accepts prompts. `dev agents` is the first-class agent hub; `dev integrate cli-agent` remains available for older scripts:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
dev agents add myagent --command myagent --arg run --input-mode prompt-file --prompt-arg=--prompt-file --supports-mcp
|
|
135
|
+
dev agents
|
|
136
|
+
dev agents doctor
|
|
137
|
+
dev agents run TASK-001 --agent myagent --profile default
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
GEPA prompt-profile optimization is available for the agent hub:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
dev agents optimize --agent codex --profile yolo --evals .devcouncil/evals/agent-profile.jsonl --dry-run
|
|
144
|
+
dev agents optimize --agent codex --profile yolo --evals .devcouncil/evals/agent-profile.jsonl --apply
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Feature Set
|
|
148
|
+
|
|
149
|
+
DevCouncil is an application layer around coding agents. It does not just emit prompts; it owns the workflow state, validates task scope, records evidence, and produces release-style reports.
|
|
150
|
+
|
|
151
|
+
### Workflow Features
|
|
152
|
+
|
|
153
|
+
- **Repository onboarding:** `dev setup` initializes `.devcouncil/`, generates the repo map + `AGENTS.md`/`CLAUDE.md` guides, scaffolds applicable engineering skills, runs environment checks, offers integration setup, and prints the next useful commands. Use `--skip-map` / `--skip-skills` to opt out, or `--scaffold-ci` to also write a starter GitHub Actions workflow.
|
|
154
|
+
- **Repository mapping:** `dev map` writes `.devcouncil/repo_map.json`, identifies important files and subsystems, filters generated/temp files, and keeps managed `AGENTS.md` / `CLAUDE.md` workspace guides synchronized. Subsystems, entry points, neighbors, and important surfaces are now inferred generically for **any** repository — grouped from the directory tree and ranked by an import-graph in-degree — so the map (and the structural context it feeds into prompts) is meaningful outside DevCouncil's own tree, not just within it. The map records the git HEAD and tracked-file fingerprint it was built from; when prompts reuse a map that has fallen behind the current code, they flag it as stale (run `dev map` to refresh) rather than silently feeding wrong structure. The map is also generated automatically on first init.
|
|
155
|
+
- **Engineering skills:** `dev skills` lists the bundled skills and shows which apply to the repository; `dev skills scaffold` writes them into `.claude/skills/<name>/SKILL.md`. A merged always-on `core-engineering` skill (think-before-coding, simplicity, surgical changes, goal-driven execution, evidence-grounded communication) plus domain skills (Android, iOS, Windows, web, AI training) that brief the agent on current SDKs, deprecations, and tooling before coding. Applicable skills are also embedded into `dev prompt` output.
|
|
156
|
+
- **CI scaffolding:** `dev scaffold-ci` writes a starter `.github/workflows/devcouncil.yml` derived from the configured test/lint/typecheck commands, filtered to the detected language stack; it never overwrites existing CI unless `--force`.
|
|
157
|
+
- **Planning council:** `dev plan` turns a goal into requirements, acceptance criteria, assumptions, critique findings, and executable tasks.
|
|
158
|
+
- **Task graph:** `dev tasks` and `dev show TASK-001` expose requirement links, acceptance-criterion links, planned files, expected tests, allowed commands, forbidden changes, dependencies, and status. Tasks can declare `depends_on`; the plan gate rejects unknown dependencies and cycles, and `dev go`/`dev e2e` run tasks in topological order and skip a task whose prerequisites didn't complete (rather than letting it fail spuriously and burn its repair budget).
|
|
159
|
+
- **Scoped task prompts:** `dev prompt TASK-001` creates a constrained implementation prompt for sidecar agents, including file scope, verification expectations, and forbidden changes. The prompt now embeds the current (secret-redacted) contents of each planned file with a top-level symbol outline, structural orientation (from the code-review graph when available, otherwise the generated `repo_map.json`), and a **dependents (blast-radius) list** — the files that import each file being changed, from the map's precomputed reverse-import index — so the agent edits in place and keeps call sites working instead of starting blind. A central prompt budget keeps the core (goal/scope/instructions) always present and fits the optional context sections in priority order (file contents > structural > dependents > skills), dropping the lowest-priority ones with an explicit marker rather than overflowing silently.
|
|
160
|
+
- **Execution:** `dev run TASK-001` supports manual sidecar mode, built-in coding CLI executors, external executors, and registered custom CLI agents.
|
|
161
|
+
- **One-command flow:** `dev e2e "goal"` and `dev go "goal"` can initialize state, plan, run approved tasks, verify the diff, and generate a report. With an automated executor the run is now a **closed loop**: a task that fails verification is re-driven through a bounded self-repair loop (a correction manifest is written and the executor re-run) until it verifies or the `execution.max_repair_attempts` budget is spent, with no-progress detection that stops early when the same blocking gaps reappear.
|
|
162
|
+
- **Verification:** `dev verify TASK-001` captures the diff, runs expected evidence commands, checks planned-file compliance, detects orphan changes, flags unplanned dependency edits, scans for secrets, and links evidence to acceptance criteria. An **empty diff can no longer pass** a task that declares files to create or modify (work that committed earlier is still recognized via the task checkpoint), and the result reports the rigor it ran at (`verification_mode` compiled vs coarse, `diff_empty`, `coverage_measured`/`coverage_skipped_reason`) plus a distinct `advisory_actions` list so an agent never mistakes "passed" for "proven." `dev verify` exits non-zero when a task is blocked so shell-driven agents can gate on `$?`.
|
|
163
|
+
- **Repair:** `dev repair` converts blocking gaps into focused follow-up work instead of leaving failures as vague test output.
|
|
164
|
+
- **Rollback:** `dev rollback TASK-001` uses task checkpoints to revert scoped work when a task needs to be backed out.
|
|
165
|
+
- **Reporting:** `dev report` emits a requirements coverage table, evidence summary, blocking gaps, and live-review blockers; JSON and PR-comment paths are available for automation.
|
|
166
|
+
|
|
167
|
+
### App Surfaces
|
|
168
|
+
|
|
169
|
+
- **CLI:** `dev` and `devcouncil` expose the same Typer command surface for local terminal workflows.
|
|
170
|
+
- **Agent hub:** `dev agents` lists built-in and custom agents, `dev agents add` registers prompt-taking CLIs, `dev agents doctor` checks wiring, `dev agents run` executes a task through a named agent/profile, and `dev agents optimize` uses GEPA to tune profile preambles from offline eval examples.
|
|
171
|
+
- **Integration hub:** `dev integrate all --apply` configures supported coding CLI and MCP integrations; targeted setup exists for Codex, Gemini, Claude Code, OpenCode, Antigravity, Cursor, Warp/Oz, hooks, and custom CLI agents. `dev integrate check` now reports each client's **enforcement posture** — `pre-action` (a native hook blocks unauthorized writes before they happen) vs `verify-only` (forbidden changes are caught only after the fact by verification) — so the containment guarantee isn't overstated for clients without a pre-action gate.
|
|
172
|
+
- **MCP server:** `dev mcp-server` exposes DevCouncil context and workflow tools over stdio for MCP-capable clients. `devcouncil_verify_task` now runs DevCouncil's strong compiled per-criterion checks when a provider key is configured (falling back to a clearly-labeled `coarse` mode otherwise), refuses to pass on an empty diff, and returns `verification_mode`, `diff_empty`, `coverage_measured`/`coverage_skipped_reason`, and an `advisory_actions` array alongside the blocking `next_actions`. Cheap, re-verify-free read tools — `devcouncil_get_gaps` and `devcouncil_get_next_actions` — let a reconnecting agent resume outstanding work from persisted gaps (which now carry `file`/`line`/`suggested_command`/`acceptance_criterion_id`). Task leases expire on a config-driven TTL so a crashed agent's task frees itself, with `devcouncil_renew_lease` and `devcouncil_list_leases` for long runs and fleet supervision; a partial-unique DB index enforces a single active lease per task, so concurrent checkouts can't both win the writer slot. A pure-MCP agent can now make the change itself through lease-gated write tools — `devcouncil_write_file` and `devcouncil_apply_patch` — which policy-check every target path *before* it lands (out-of-scope, protected, or escaping paths are rejected; a patch with any out-of-scope target is rejected whole, never partially applied), write atomically, and record a `FileChangeEvent` for provenance. The corpus is also browsable as MCP **resources** (`devcouncil://report`, `devcouncil://tasks`, `devcouncil://gaps`, `devcouncil://cards`, `devcouncil://task/{id}`) so a host can read project state without a tool call. `devcouncil_get_task_provenance` then exposes that audit trail — gated file changes, verification runs, diff-coverage evidence, and the latest correction manifest — so what happened on disk is inspectable. The diff↔coverage proof is now also retained across graph reloads (it was previously dropped), so reports and `dev status` reflect whether the changed lines were actually exercised.
|
|
173
|
+
- **Live review:** `dev watch` tracks review cards, signals, blocking feedback, and repair guidance while a session is active.
|
|
174
|
+
- **Trace viewer:** `dev trace tail --follow` streams local DevCouncil trace events for execution, verification, and agent handoff.
|
|
175
|
+
- **Dashboard:** `dev dashboard --open` serves a local status dashboard and opens it in the default browser for project state and live workflow visibility.
|
|
176
|
+
- **Agent-consumable CLI:** machine output for shell-driven agents — `dev prompt --json` (`{ok, task_id, prompt}`), `dev handoff --json` (`{ok, manifest_path, run_id, next_command}` to chain `dev run`), `dev verify` exits non-zero when blocked, and `dev status`/`dev report` accept `--fail-on-blocking` to exit non-zero on outstanding blocking gaps so a loop can gate on `$?`.
|
|
177
|
+
- **Config editor:** `dev config` and `dev config models` inspect/update provider, model, executor, and command configuration.
|
|
178
|
+
- **Artifact tools:** `dev artifacts validate` checks stored graph integrity.
|
|
179
|
+
- **Code intelligence:** `dev lsp inspect` checks optional language-server readiness, and `dev ast match` searches code structurally.
|
|
180
|
+
- **Doctor:** `dev doctor` validates local dependencies, commands, and environment prerequisites before a workflow fails deeper in execution.
|
|
181
|
+
|
|
182
|
+
### Agent And Executor Support
|
|
183
|
+
|
|
184
|
+
DevCouncil works with human-in-the-loop sidecar sessions and automated prompt handoff:
|
|
185
|
+
|
|
186
|
+
- **Manual sidecar:** paste `dev prompt TASK-001` into any agent, then run `dev verify TASK-001`.
|
|
187
|
+
- **Built-in coding CLI adapters:** `codex`, `gemini`, `claude`, `opencode`, `antigravity`, `warp`, `cursor`, `aider`, and aliases such as `codex-cli`, `gemini-cli`, `claude-code`, `opencode-cli`, `antigravity-cli`, `agy`, `agy-cli`, `warp-cli`, `oz`, `cursor-agent`, and `cursor-cli`.
|
|
188
|
+
- **Custom CLI agents:** register any prompt-taking command with stdin, argument, or prompt-file handoff.
|
|
189
|
+
- **Execution profiles:** custom agents can use profiles such as `default`, `yolo`, and `prod` to adjust prompt constraints while DevCouncil still verifies the final diff.
|
|
190
|
+
- **External automated adapters:** `mini`, `openhands`, `native-preview`, and `native` are available when the corresponding local executor is configured.
|
|
191
|
+
- **Hook-aware clients:** `dev integrate hooks --apply` installs write/shell hooks for Codex, Gemini, Claude, Cursor, and OpenCode so DevCouncil policy can block unauthorized actions before verification. The post-task hook can run deterministic verification of the active task and record gaps (enable `execution.verify_on_post_task`; off by default to keep hooks fast). File-write policy uses one shared path normalizer across the hook and task-policy paths that resolves every target and **denies anything outside the project root** (so the path that's checked is the path that's enforced), and the pre-tool-use hook is fail-closed: an unparseable or error payload is surfaced (and blocked under `--strict`/`DEVCOUNCIL_HOOK_STRICT`) rather than silently allowed.
|
|
192
|
+
|
|
193
|
+
### Gates And Evidence
|
|
194
|
+
|
|
195
|
+
DevCouncil blocks completion on concrete gaps rather than model confidence:
|
|
196
|
+
|
|
197
|
+
- **Plan approval gates:** requirements must have acceptance criteria, acceptance criteria need verification methods, tasks must map to known requirements and acceptance criteria, high-impact assumptions must be resolved, and high/critical critique findings must be closed.
|
|
198
|
+
- **Task readiness gates:** the working tree must be clean for the task, planned files must be declared, and each task needs allowed commands plus expected verification evidence.
|
|
199
|
+
- **Diff gates:** verification detects files changed outside the planned task scope, dependency-file edits made without authorization, deleted/added files, and untracked file diffs.
|
|
200
|
+
- **Evidence gates:** passing evidence commands are linked back to acceptance criteria; missing passing evidence becomes a blocking gap.
|
|
201
|
+
- **Security gates:** secret scanning runs over captured diffs, and command output is redacted before it is written to logs.
|
|
202
|
+
- **Live-review gates:** unresolved critical review cards can block task verification and appear in reports.
|
|
203
|
+
|
|
204
|
+
### Providers, Models, And Cost Tracking
|
|
205
|
+
|
|
206
|
+
- **Providers:** OpenRouter, Vertex AI, Doubleword, and Ollama (local, no key) are supported through local configuration and secrets.
|
|
207
|
+
- **Role models:** planner, critic, arbiter, reviewer, and repair roles can share one model or use per-role overrides.
|
|
208
|
+
- **Structured repair:** model routing includes JSON repair paths for structured planning and review outputs.
|
|
209
|
+
- **Model defaults:** packaged YAML defaults ship with the tool so installed CLI environments do not depend on source-tree-only files.
|
|
210
|
+
- **Telemetry:** local trace and cost data feed `dev status`, reports, and dashboard surfaces.
|
|
211
|
+
|
|
212
|
+
### Reports And Automation Outputs
|
|
213
|
+
|
|
214
|
+
- **Markdown reports:** include verdict, coverage summary, requirement/task mapping, blocking gaps, and live-review status.
|
|
215
|
+
- **JSON reports:** `--json` and `--report-file` support machine-readable handoff to other automation.
|
|
216
|
+
- **Agent preset:** `--agent` writes `.devcouncil/reports/latest.json` for stable downstream consumption.
|
|
217
|
+
- **PR comments:** `dev report --github-pr-comment` and `dev report --gitlab-pr-comment` can publish verification summaries to pull/merge requests.
|
|
218
|
+
- **GitHub checks:** preview GitHub report/check surfaces are available for repository automation.
|
|
219
|
+
|
|
220
|
+
### Local State And Files
|
|
221
|
+
|
|
222
|
+
DevCouncil stores local workflow state in the target repository:
|
|
223
|
+
|
|
224
|
+
- `.devcouncil/config.yaml`: provider, executor, command, integration, and workflow settings.
|
|
225
|
+
- `.devcouncil/secrets.env`: local provider secrets such as API keys or Vertex AI project/location values. Git-ignored; copy `.devcouncil/secrets.env.example` and fill in real values. Environment variables take precedence over this file.
|
|
226
|
+
- `.devcouncil/repo_map.json`: generated repository map and subsystem navigation index.
|
|
227
|
+
- `.devcouncil/state.sqlite`: SQLite state for requirements, assumptions, tasks, evidence, gaps, critique findings, and project phase history.
|
|
228
|
+
- `.devcouncil/checkpoints/`: task snapshots used by verification and rollback.
|
|
229
|
+
- `.devcouncil/logs/`: redacted stdout/stderr from verification commands.
|
|
230
|
+
- `.devcouncil/runs/<run-id>/agent-run.json`: prompt, executor, profile, exit status, and run metadata for automated agent executions.
|
|
231
|
+
- `.devcouncil/reports/latest.json`: optional machine-readable report generated by `dev e2e --agent`.
|
|
232
|
+
- `.devcouncil/integrations/` and `.agents/`: generated integration files such as Warp/Oz MCP JSON and Antigravity MCP config.
|
|
233
|
+
|
|
234
|
+
### Maturity
|
|
235
|
+
|
|
236
|
+
The stable daily workflow is planning, manual sidecar execution, verification, repair, rollback, and reporting. Coding CLI executors, MCP, live review, dashboard, PR comments, LSP/AST tools, and GitHub check surfaces are preview features. Native autonomous execution is experimental and still requires DevCouncil verification before work is considered complete.
|
|
237
|
+
|
|
98
238
|
## Core Flow
|
|
99
239
|
|
|
100
240
|
DevCouncil's recommended default is **Manual Sidecar Mode**:
|
|
@@ -108,6 +248,50 @@ DevCouncil's recommended default is **Manual Sidecar Mode**:
|
|
|
108
248
|
|
|
109
249
|
The detailed task-by-task workflow lives in [docs/workflow.md](docs/workflow.md).
|
|
110
250
|
|
|
251
|
+
## How The Repo Runs
|
|
252
|
+
|
|
253
|
+
```mermaid
|
|
254
|
+
flowchart TD
|
|
255
|
+
user["User runs dev/devcouncil"] --> cli["Typer CLI\nsrc/devcouncil/cli/main.py"]
|
|
256
|
+
cli --> config["Config + secrets\n.devcouncil/config.yaml\n.devcouncil/secrets.env"]
|
|
257
|
+
cli --> map["Repo map\nsrc/devcouncil/indexing/repo_mapper.py"]
|
|
258
|
+
cli --> planning["Planning commands\ndev plan / dev prompt / dev tasks"]
|
|
259
|
+
|
|
260
|
+
config --> providers["Model providers\nOpenRouter, Vertex AI, Doubleword, or Ollama"]
|
|
261
|
+
providers --> router["ModelRouter\nrole models, cache, telemetry, structured JSON repair"]
|
|
262
|
+
router --> planning
|
|
263
|
+
|
|
264
|
+
planning --> storage["SQLite + repositories\nrequirements, tasks, gaps, evidence, state"]
|
|
265
|
+
storage --> artifactGraph["Artifact graph\nRequirement -> Task -> Diff -> Evidence"]
|
|
266
|
+
artifactGraph --> gates["Gate policy\nplanned files, commands, secret checks"]
|
|
267
|
+
|
|
268
|
+
gates --> manual["Manual sidecar\ndev prompt + user agent edits"]
|
|
269
|
+
gates --> coding["Coding CLI executor\nCodex, Gemini, Claude, OpenCode, Antigravity, Warp, custom CLIs"]
|
|
270
|
+
gates --> native["Native preview executor\nLLM router + TaskRunner"]
|
|
271
|
+
gates --> external["Mini-SWE / OpenHands adapters"]
|
|
272
|
+
|
|
273
|
+
coding --> runlog["Run artifacts\nprompt file, redacted logs, manifest, trace events"]
|
|
274
|
+
native --> runlog
|
|
275
|
+
external --> runlog
|
|
276
|
+
manual --> diff["Repository diff"]
|
|
277
|
+
runlog --> diff
|
|
278
|
+
|
|
279
|
+
diff --> verify["Verifier\ndev verify / automatic post-run verification"]
|
|
280
|
+
verify --> evidence["Evidence + gaps"]
|
|
281
|
+
evidence --> storage
|
|
282
|
+
evidence --> repair["Repair loop\ndev repair / dev watch repair"]
|
|
283
|
+
evidence --> report["Reports\ndev report, JSON, GitHub/GitLab comments"]
|
|
284
|
+
|
|
285
|
+
cli --> mcp["MCP server\ndev mcp-server"]
|
|
286
|
+
mcp --> storage
|
|
287
|
+
mcp --> artifactGraph
|
|
288
|
+
mcp --> repair
|
|
289
|
+
|
|
290
|
+
cli --> live["Live review\ndev watch"]
|
|
291
|
+
live --> cards["Cards + signals\nblocking review feedback"]
|
|
292
|
+
cards --> report
|
|
293
|
+
```
|
|
294
|
+
|
|
111
295
|
## Install From Source
|
|
112
296
|
|
|
113
297
|
For local development inside this checkout:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devcouncil",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Gated orchestrator for AI-assisted software development",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/bharathvbcr/DevCouncil#readme",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"bin/",
|
|
28
28
|
"src/**/*.py",
|
|
29
29
|
"src/**/*.md",
|
|
30
|
+
"src/**/*.png",
|
|
31
|
+
"src/**/*.svg",
|
|
32
|
+
"src/**/*.yaml",
|
|
33
|
+
"src/**/*.mjs",
|
|
30
34
|
"pyproject.toml",
|
|
31
35
|
"uv.lock",
|
|
32
36
|
"README.md",
|
|
@@ -37,9 +41,12 @@
|
|
|
37
41
|
"install:editable": "uv pip install -e .",
|
|
38
42
|
"dev": "uv run devcouncil",
|
|
39
43
|
"pack:check": "npm pack --dry-run",
|
|
44
|
+
"smoke:wheel": "uv run python scripts/check-wheel-assets.py",
|
|
45
|
+
"smoke:package": "node scripts/npm-runtime-smoke.mjs",
|
|
40
46
|
"test": "uv run pytest",
|
|
41
47
|
"lint": "uv run ruff check .",
|
|
42
|
-
"
|
|
48
|
+
"typecheck": "uv run mypy src",
|
|
49
|
+
"check": "uv run ruff check . && uv run mypy src && uv run pytest"
|
|
43
50
|
},
|
|
44
51
|
"engines": {
|
|
45
52
|
"node": ">=18"
|
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "devcouncil"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Gated orchestrator for AI-assisted software development"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -11,10 +11,17 @@ dependencies = [
|
|
|
11
11
|
"pyyaml>=6.0.1",
|
|
12
12
|
"sqlmodel>=0.0.19",
|
|
13
13
|
"httpx>=0.27.0",
|
|
14
|
-
"gitpython>=3.1.
|
|
14
|
+
"gitpython>=3.1.49",
|
|
15
15
|
"mcp>=1.27.0",
|
|
16
|
+
"gepa>=0.1.1",
|
|
17
|
+
"watchdog>=4.0.0",
|
|
16
18
|
]
|
|
17
19
|
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://github.com/bharathvbcr/DevCouncil"
|
|
22
|
+
Repository = "https://github.com/bharathvbcr/DevCouncil.git"
|
|
23
|
+
Issues = "https://github.com/bharathvbcr/DevCouncil/issues"
|
|
24
|
+
|
|
18
25
|
[project.scripts]
|
|
19
26
|
dev = "devcouncil.cli.main:app"
|
|
20
27
|
devcouncil = "devcouncil.cli.main:app"
|
|
@@ -24,6 +31,24 @@ dev = [
|
|
|
24
31
|
"pytest>=8.2.0",
|
|
25
32
|
"ruff>=0.4.4",
|
|
26
33
|
"mypy>=1.10.0",
|
|
34
|
+
"types-pyyaml>=6.0.12.20260408",
|
|
35
|
+
# Used only to exercise the diff↔coverage path end-to-end in tests. DevCouncil
|
|
36
|
+
# never requires coverage at runtime — it uses whatever the target repo provides.
|
|
37
|
+
"coverage>=7.4",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.uv]
|
|
41
|
+
# Security floors for transitive dependencies (Dependabot advisories, 2026-06).
|
|
42
|
+
# These are not direct deps; constraint-dependencies pins their minimum patched
|
|
43
|
+
# version in the resolver without adding them to the dependency tree, so they can
|
|
44
|
+
# never resolve back below the fix.
|
|
45
|
+
constraint-dependencies = [
|
|
46
|
+
"cryptography>=48.0.1",
|
|
47
|
+
"starlette>=1.3.1",
|
|
48
|
+
"pyjwt>=2.13.0",
|
|
49
|
+
"python-multipart>=0.0.31",
|
|
50
|
+
"pydantic-settings>=2.14.2",
|
|
51
|
+
"idna>=3.15",
|
|
27
52
|
]
|
|
28
53
|
|
|
29
54
|
[tool.pytest.ini_options]
|
|
@@ -32,3 +57,10 @@ testpaths = ["tests"]
|
|
|
32
57
|
[build-system]
|
|
33
58
|
requires = ["hatchling"]
|
|
34
59
|
build-backend = "hatchling.build"
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
62
|
+
"src/devcouncil/llm/model_defaults.yaml" = "devcouncil/llm/model_defaults.yaml"
|
|
63
|
+
"src/devcouncil/telemetry/model_pricing.yaml" = "devcouncil/telemetry/model_pricing.yaml"
|
|
64
|
+
"src/devcouncil/assets/devcouncil-logo.svg" = "devcouncil/assets/devcouncil-logo.svg"
|
|
65
|
+
"src/devcouncil/assets/devcouncil_logo_premium.png" = "devcouncil/assets/devcouncil_logo_premium.png"
|
|
66
|
+
"src/devcouncil/integrations/opencode_devcouncil_plugin.mjs" = "devcouncil/integrations/opencode_devcouncil_plugin.mjs"
|
|
@@ -6,6 +6,8 @@ Replaces scattered yaml.safe_load() calls with a single validated config service
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
9
11
|
from pathlib import Path
|
|
10
12
|
from typing import Dict, List
|
|
11
13
|
|
|
@@ -34,6 +36,34 @@ class CommandsConfig(BaseModel):
|
|
|
34
36
|
typecheck: List[str] = Field(default_factory=list)
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
class VerificationSandboxConfig(BaseModel):
|
|
40
|
+
docker_image: str = "python:3.12-slim"
|
|
41
|
+
docker_setup_commands: List[str] = Field(default_factory=list)
|
|
42
|
+
nix_flake_attr: str | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DiffCoverageConfig(BaseModel):
|
|
46
|
+
"""Diff↔coverage gating: prove the *changed* lines were exercised by tests.
|
|
47
|
+
|
|
48
|
+
``measure`` runs the diff-coverage analysis and records it as evidence (and a
|
|
49
|
+
non-blocking signal) whenever the target repo's coverage tooling is present.
|
|
50
|
+
``enforce`` promotes an unexercised diff to a *blocking* gap. Enforcement is
|
|
51
|
+
off by default so the signal is visible before it ever gates — a passing test
|
|
52
|
+
that does not touch the new code is surfaced first, then teams opt in to
|
|
53
|
+
blocking. ``min_ratio`` of 0.0 means "require at least one changed executable
|
|
54
|
+
line to be exercised"; a higher value demands that fraction of changed lines.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
measure: bool = True
|
|
58
|
+
enforce: bool = False
|
|
59
|
+
min_ratio: float = 0.0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class VerificationConfig(BaseModel):
|
|
63
|
+
sandbox: VerificationSandboxConfig = Field(default_factory=VerificationSandboxConfig)
|
|
64
|
+
diff_coverage: DiffCoverageConfig = Field(default_factory=DiffCoverageConfig)
|
|
65
|
+
|
|
66
|
+
|
|
37
67
|
class GatesConfig(BaseModel):
|
|
38
68
|
require_clean_git_before_task: bool = True
|
|
39
69
|
block_orphan_diffs: bool = True
|
|
@@ -48,6 +78,16 @@ class ExecutionConfig(BaseModel):
|
|
|
48
78
|
max_repair_attempts: int = 3
|
|
49
79
|
checkpoint_before_each_task: bool = True
|
|
50
80
|
command_timeout: int = 300
|
|
81
|
+
stream_cli_output: bool = False
|
|
82
|
+
# Default lifetime of an MCP task lease. A crashed/disconnected agent's lease
|
|
83
|
+
# auto-expires after this, so the task frees up without a human running force.
|
|
84
|
+
lease_ttl_seconds: int = 1800
|
|
85
|
+
# When true, the post-task coding-CLI hook runs deterministic verification of the
|
|
86
|
+
# active task (and records gaps) instead of only printing a reminder. Off by default
|
|
87
|
+
# so hooks stay fast/cheap unless a team opts in.
|
|
88
|
+
verify_on_post_task: bool = False
|
|
89
|
+
cursor_resume_mode: str = "off"
|
|
90
|
+
coding_cli_probe_order: List[str] = Field(default_factory=list)
|
|
51
91
|
|
|
52
92
|
|
|
53
93
|
class PrivacyConfig(BaseModel):
|
|
@@ -75,10 +115,89 @@ class LiveReviewIntegrationConfig(BaseModel):
|
|
|
75
115
|
default_client: str = "claude"
|
|
76
116
|
|
|
77
117
|
|
|
118
|
+
class WarpIntegrationConfig(BaseModel):
|
|
119
|
+
enabled: bool = False
|
|
120
|
+
command: str = "oz"
|
|
121
|
+
run_mode: str = "local"
|
|
122
|
+
mcp_config_path: str = ".devcouncil/integrations/warp-mcp.json"
|
|
123
|
+
profile: str | None = None
|
|
124
|
+
model: str | None = None
|
|
125
|
+
environment: str | None = None
|
|
126
|
+
share: List[str] = Field(default_factory=list)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class OpenCodeIntegrationConfig(BaseModel):
|
|
130
|
+
enabled: bool = False
|
|
131
|
+
config_path: str = "opencode.json"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class AntigravityIntegrationConfig(BaseModel):
|
|
135
|
+
enabled: bool = False
|
|
136
|
+
mcp_config_path: str = ".agents/mcp_config.json"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class CursorIntegrationConfig(BaseModel):
|
|
140
|
+
enabled: bool = False
|
|
141
|
+
config_path: str = ".cursor/mcp.json"
|
|
142
|
+
hooks_path: str = ".cursor/hooks.json"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class AiderIntegrationConfig(BaseModel):
|
|
146
|
+
enabled: bool = False
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class CliAgentProfileConfig(BaseModel):
|
|
150
|
+
description: str = ""
|
|
151
|
+
timeout_seconds: int | None = None
|
|
152
|
+
prompt_preamble: str = ""
|
|
153
|
+
require_explicit_confirmation: bool = False
|
|
154
|
+
# Per-profile CLI containment overrides. Empty/None reproduce today's behavior
|
|
155
|
+
# exactly so a profile that only sets a prompt preamble is a no-op on the
|
|
156
|
+
# subprocess invocation. ``extra_args`` are appended verbatim to the resolved
|
|
157
|
+
# command, ``permission_mode`` is translated into the right per-CLI flag where
|
|
158
|
+
# known (and overly-permissive flags are dropped for stricter modes), and
|
|
159
|
+
# ``model`` overrides the model flag for CLIs that accept one.
|
|
160
|
+
extra_args: List[str] = Field(default_factory=list)
|
|
161
|
+
permission_mode: str | None = None
|
|
162
|
+
model: str | None = None
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class CustomCliAgentConfig(BaseModel):
|
|
166
|
+
command: str
|
|
167
|
+
args: List[str] = Field(default_factory=list)
|
|
168
|
+
input_mode: str = "stdin"
|
|
169
|
+
prompt_arg: str | None = None
|
|
170
|
+
timeout_seconds: int | None = None
|
|
171
|
+
env: Dict[str, str] = Field(default_factory=dict)
|
|
172
|
+
display_name: str | None = None
|
|
173
|
+
kind: str = "custom"
|
|
174
|
+
supports_mcp: bool = False
|
|
175
|
+
supports_diff_review: bool = False
|
|
176
|
+
default_profile: str = "default"
|
|
177
|
+
help_command: List[str] = Field(default_factory=list)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class CliAgentsIntegrationConfig(BaseModel):
|
|
181
|
+
enabled: bool = True
|
|
182
|
+
profiles: Dict[str, CliAgentProfileConfig] = Field(default_factory=dict)
|
|
183
|
+
agents: Dict[str, CustomCliAgentConfig] = Field(default_factory=dict)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class McpIntegrationConfig(BaseModel):
|
|
187
|
+
write_task_scope_to_config: bool = False
|
|
188
|
+
|
|
189
|
+
|
|
78
190
|
class IntegrationsConfig(BaseModel):
|
|
191
|
+
mcp: McpIntegrationConfig = Field(default_factory=McpIntegrationConfig)
|
|
79
192
|
agent_flow: AgentFlowIntegrationConfig = Field(default_factory=AgentFlowIntegrationConfig)
|
|
80
193
|
code_review_graph: CodeReviewGraphIntegrationConfig = Field(default_factory=CodeReviewGraphIntegrationConfig)
|
|
81
194
|
live_review: LiveReviewIntegrationConfig = Field(default_factory=LiveReviewIntegrationConfig)
|
|
195
|
+
cursor: CursorIntegrationConfig = Field(default_factory=CursorIntegrationConfig)
|
|
196
|
+
aider: AiderIntegrationConfig = Field(default_factory=AiderIntegrationConfig)
|
|
197
|
+
antigravity: AntigravityIntegrationConfig = Field(default_factory=AntigravityIntegrationConfig)
|
|
198
|
+
warp: WarpIntegrationConfig = Field(default_factory=WarpIntegrationConfig)
|
|
199
|
+
opencode: OpenCodeIntegrationConfig = Field(default_factory=OpenCodeIntegrationConfig)
|
|
200
|
+
cli_agents: CliAgentsIntegrationConfig = Field(default_factory=CliAgentsIntegrationConfig)
|
|
82
201
|
|
|
83
202
|
|
|
84
203
|
class ProviderConfig(BaseModel):
|
|
@@ -97,6 +216,7 @@ class DevCouncilConfig(BaseModel):
|
|
|
97
216
|
commands: CommandsConfig = Field(default_factory=CommandsConfig)
|
|
98
217
|
gates: GatesConfig = Field(default_factory=GatesConfig)
|
|
99
218
|
execution: ExecutionConfig = Field(default_factory=ExecutionConfig)
|
|
219
|
+
verification: VerificationConfig = Field(default_factory=VerificationConfig)
|
|
100
220
|
privacy: PrivacyConfig = Field(default_factory=PrivacyConfig)
|
|
101
221
|
integrations: IntegrationsConfig = Field(default_factory=IntegrationsConfig)
|
|
102
222
|
|
|
@@ -107,25 +227,38 @@ def load_config(project_root: Path = Path(".")) -> DevCouncilConfig:
|
|
|
107
227
|
Returns DevCouncilConfig with defaults for any missing fields.
|
|
108
228
|
Raises FileNotFoundError if config doesn't exist.
|
|
109
229
|
"""
|
|
110
|
-
import yaml
|
|
230
|
+
import yaml # type: ignore[import-untyped]
|
|
111
231
|
|
|
112
232
|
config_path = project_root / ".devcouncil" / "config.yaml"
|
|
113
233
|
if not config_path.exists():
|
|
114
234
|
raise FileNotFoundError(f"Config not found at {config_path}. Run 'dev init' first.")
|
|
115
235
|
|
|
116
|
-
with open(config_path) as f:
|
|
117
|
-
|
|
236
|
+
with open(config_path, encoding="utf-8") as f:
|
|
237
|
+
try:
|
|
238
|
+
raw = yaml.safe_load(f) or {}
|
|
239
|
+
except yaml.YAMLError as exc:
|
|
240
|
+
raise ValueError(
|
|
241
|
+
f"Invalid YAML in {config_path}: {exc}. Fix the syntax or re-run 'dev init'."
|
|
242
|
+
) from exc
|
|
118
243
|
|
|
119
244
|
return DevCouncilConfig.model_validate(raw)
|
|
120
245
|
|
|
121
246
|
|
|
122
247
|
def provider_api_key_env_var(provider: str = "openrouter") -> str:
|
|
248
|
+
normalized = provider.strip().lower().replace("-", "").replace("_", "")
|
|
123
249
|
env_map = {
|
|
124
250
|
"openrouter": "OPENROUTER_API_KEY",
|
|
251
|
+
"vertexai": "VERTEXAI_ACCESS_TOKEN",
|
|
252
|
+
"doubleword": "DOUBLEWORD_API_KEY",
|
|
253
|
+
"ollama": "OLLAMA_API_KEY",
|
|
125
254
|
"openai": "OPENAI_API_KEY",
|
|
126
255
|
"anthropic": "ANTHROPIC_API_KEY",
|
|
127
256
|
}
|
|
128
|
-
return env_map.get(
|
|
257
|
+
return env_map.get(normalized, f"{normalized.upper()}_API_KEY")
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _normalized_provider_name(provider: str) -> str:
|
|
261
|
+
return provider.strip().lower().replace("-", "").replace("_", "")
|
|
129
262
|
|
|
130
263
|
|
|
131
264
|
def load_local_secrets(project_root: Path = Path(".")) -> Dict[str, str]:
|
|
@@ -143,6 +276,24 @@ def load_local_secrets(project_root: Path = Path(".")) -> Dict[str, str]:
|
|
|
143
276
|
return secrets
|
|
144
277
|
|
|
145
278
|
|
|
279
|
+
def get_gcloud_access_token() -> str | None:
|
|
280
|
+
executable = shutil.which("gcloud")
|
|
281
|
+
if not executable:
|
|
282
|
+
return None
|
|
283
|
+
try:
|
|
284
|
+
token = subprocess.check_output(
|
|
285
|
+
[executable, "auth", "print-access-token"],
|
|
286
|
+
stderr=subprocess.STDOUT,
|
|
287
|
+
text=True,
|
|
288
|
+
encoding="utf-8",
|
|
289
|
+
errors="replace",
|
|
290
|
+
timeout=10,
|
|
291
|
+
).strip()
|
|
292
|
+
except Exception:
|
|
293
|
+
return None
|
|
294
|
+
return token or None
|
|
295
|
+
|
|
296
|
+
|
|
146
297
|
def get_api_key(provider: str = "openrouter", project_root: Path = Path(".")) -> str:
|
|
147
298
|
"""Retrieve the API key for the configured provider from environment.
|
|
148
299
|
|
|
@@ -150,9 +301,20 @@ def get_api_key(provider: str = "openrouter", project_root: Path = Path(".")) ->
|
|
|
150
301
|
"""
|
|
151
302
|
env_var = provider_api_key_env_var(provider)
|
|
152
303
|
key = os.environ.get(env_var) or load_local_secrets(project_root).get(env_var)
|
|
304
|
+
if not key and _normalized_provider_name(provider) == "vertexai":
|
|
305
|
+
key = get_gcloud_access_token()
|
|
306
|
+
if not key and _normalized_provider_name(provider) == "ollama":
|
|
307
|
+
# Ollama is a local server and needs no API key; an explicitly-set
|
|
308
|
+
# OLLAMA_API_KEY still flows through above if present.
|
|
309
|
+
return ""
|
|
153
310
|
if not key:
|
|
311
|
+
extra = (
|
|
312
|
+
" You can also authenticate with 'gcloud auth login' for vertexai."
|
|
313
|
+
if _normalized_provider_name(provider) == "vertexai"
|
|
314
|
+
else ""
|
|
315
|
+
)
|
|
154
316
|
raise ValueError(
|
|
155
317
|
f"API key not found. Set {env_var} in your environment or run 'dev setup'. "
|
|
156
|
-
f"Provider: {provider}"
|
|
318
|
+
f"Provider: {provider}.{extra}"
|
|
157
319
|
)
|
|
158
320
|
return key
|
|
@@ -18,7 +18,7 @@ from typing import Any, Dict, List, Set, Tuple
|
|
|
18
18
|
from devcouncil.domain.requirement import Requirement, AcceptanceCriterion
|
|
19
19
|
from devcouncil.domain.task import Task
|
|
20
20
|
from devcouncil.domain.assumption import Assumption
|
|
21
|
-
from devcouncil.domain.evidence import CommandResult, DiffEvidence, TestEvidence
|
|
21
|
+
from devcouncil.domain.evidence import CommandResult, DiffCoverageEvidence, DiffEvidence, TestEvidence
|
|
22
22
|
from devcouncil.domain.gap import Gap
|
|
23
23
|
from devcouncil.domain.critique import CritiqueFinding
|
|
24
24
|
|
|
@@ -35,6 +35,7 @@ class ArtifactGraph:
|
|
|
35
35
|
test_evidence: List[TestEvidence] = field(default_factory=list)
|
|
36
36
|
diff_evidence: List[DiffEvidence] = field(default_factory=list)
|
|
37
37
|
command_results: List[CommandResult] = field(default_factory=list)
|
|
38
|
+
diff_coverage_evidence: List[DiffCoverageEvidence] = field(default_factory=list)
|
|
38
39
|
|
|
39
40
|
# --- Mutation ---
|
|
40
41
|
|
|
@@ -62,6 +63,17 @@ class ArtifactGraph:
|
|
|
62
63
|
def add_command_result(self, cr: CommandResult) -> None:
|
|
63
64
|
self.command_results.append(cr)
|
|
64
65
|
|
|
66
|
+
def add_diff_coverage_evidence(self, ev: DiffCoverageEvidence) -> None:
|
|
67
|
+
self.diff_coverage_evidence.append(ev)
|
|
68
|
+
|
|
69
|
+
def diff_coverage_findings(self) -> List[DiffCoverageEvidence]:
|
|
70
|
+
"""Measured diff-coverage runs where the changed lines were NOT fully exercised
|
|
71
|
+
— i.e. a green suite that did not actually run the new code."""
|
|
72
|
+
return [
|
|
73
|
+
ev for ev in self.diff_coverage_evidence
|
|
74
|
+
if ev.measured and ev.changed_lines and ev.covered_lines < ev.changed_lines
|
|
75
|
+
]
|
|
76
|
+
|
|
65
77
|
# --- Coverage Queries ---
|
|
66
78
|
|
|
67
79
|
def requirements_without_tasks(self) -> List[Requirement]:
|
|
@@ -80,10 +92,16 @@ class ArtifactGraph:
|
|
|
80
92
|
return [r for r in self.requirements.values() if not r.acceptance_criteria]
|
|
81
93
|
|
|
82
94
|
def acceptance_criteria_without_evidence(self) -> List[Tuple[str, AcceptanceCriterion]]:
|
|
83
|
-
"""AC IDs that have no test evidence mapped to them.
|
|
95
|
+
"""AC IDs that have no *passing* test evidence mapped to them.
|
|
96
|
+
|
|
97
|
+
Only ``passed`` evidence counts: a failed or not-run check is not proof, so
|
|
98
|
+
it must not remove a criterion from the unproven list (which would feed a
|
|
99
|
+
falsely-green coverage summary to ``dev status`` and the MCP surface).
|
|
100
|
+
"""
|
|
84
101
|
evidenced_ac_ids: Set[str] = set()
|
|
85
102
|
for ev in self.test_evidence:
|
|
86
|
-
|
|
103
|
+
if getattr(ev, "status", "passed") == "passed":
|
|
104
|
+
evidenced_ac_ids.add(ev.acceptance_criterion_id)
|
|
87
105
|
|
|
88
106
|
results: List[Tuple[str, AcceptanceCriterion]] = []
|
|
89
107
|
for req in self.requirements.values():
|
|
@@ -137,6 +155,8 @@ class ArtifactGraph:
|
|
|
137
155
|
"ac_without_evidence": len(self.acceptance_criteria_without_evidence()),
|
|
138
156
|
"total_gaps": len(self.gaps),
|
|
139
157
|
"blocking_gaps": len(self.blocking_gaps()),
|
|
158
|
+
"diff_coverage_runs": len(self.diff_coverage_evidence),
|
|
159
|
+
"unexercised_diff_findings": len(self.diff_coverage_findings()),
|
|
140
160
|
"open_findings": len(self.open_findings()),
|
|
141
161
|
"high_critical_open_findings": len(self.open_findings("high")),
|
|
142
162
|
"unconfirmed_high_assumptions": len(self.unconfirmed_high_impact_assumptions()),
|