Verification-Driven Development Framework
⚠️ Alpha (v0.x), no longer under active development. Quacking reached an alpha state but is not currently being maintained. The code is published as-is for reference and experimentation; expect rough edges and no guarantee of fixes or new features. Forks and PRs are welcome.
Quacking is a multi-agent orchestration system for high-integrity software engineering. It uses review AI agents to ensure code implementations match their specifications through continuous verification loops.
Quacking implements a novel development methodology where:
- Planning Phase: You work with the Planning Agent to create the Canonical Specification---the authoritative requirements document including traps and edge cases
- The Planning Agent then creates a build plan and derives the Builder Specification (canonical spec with traps/secrets removed)
- Build Loop: A Builder Agent implements features step-by-step, with access only to the derived spec
- Reviewer Agents review implementations against the full canonical spec
- A Spec Manager transforms findings into feedback without revealing canonical secrets, and manages Builder Spec updates throughout the process
- The loop continues until all steps pass review
This review approach imitates the separation of roles in mature development processes, with the goal of improving both correctness and cost efficiency.
- Python 3.13 or higher
- Git
- An Anthropic API key
# Clone the repository
git clone https://github.com/abwagner/quacking.git
cd quacking
# Install with uv (recommended)
uv sync
# Install with development tools
uv sync --extra dev
# Install with the NiceGUI dashboard
uv sync --extra gui-next
# Install everything
uv sync --all-extrasTests under tests/gui_next/ require the gui-next extra. To run the suite without installing GUI deps, add --ignore=tests/gui_next when invoking pytest. Integration tests mock the Anthropic API, so a real key is not required to run them.
Note: the older Streamlit GUI (
--extra gui, code undersrc/quacking/gui/) is deprecated. New work should target the NiceGUI-basedgui_next. The Streamlit code will be removed in a future release.
API Key
export ANTHROPIC_API_KEY="your-api-key-here"OAuth credentials take precedence over the environment variable if both are available.
# Initialize a new project
quacking init my-project --spec path/to/specification.md
# Navigate to project
cd my-project
# Run the build process
quacking run
# Check status
quacking status
# View and resolve any escalations
quacking escalationsThe CLI provides full control over the VDD process through simple commands.
# Initialize in current directory
quacking init
# Initialize with a project name (creates subdirectory)
quacking init my-project
# Initialize with a specification file
quacking init --spec path/to/canonical-spec.mdThis creates:
my-project/
└── .quacking/
├── config.toml # Quacking configuration
├── projects/
├── specs/
├── history/
└── escalations/
# Run with default spec location (.quacking/specs/canonical.md)
quacking run
# Run with specific spec file
quacking run --spec path/to/spec.md
# Resume from checkpoint
quacking run --resume
# Dry run (planning only, no execution)
quacking run --dry-run# Show current status
quacking status
# Output as JSON (for scripting)
quacking status --json
# View build history
quacking history
# View history as table
quacking history --format table
# View history as JSON
quacking history --format json# Pause after current step
quacking pause
# Resume paused orchestration
quacking resumeEscalations are decisions that require human input.
# List pending escalations
quacking escalations
# Resolve an escalation
quacking escalations --resolve ESC-001 --decision 0
# Resolve with rationale
quacking escalations --resolve ESC-001 --decision 0 --rationale "Approved for MVP"# Run pre-commit hooks
quacking ci pre-commit
# Run post-commit CI suite
quacking ci post-commit abc123def# Verify all prerequisites
quacking doctorOutput:
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Check ┃ Status ┃ Details ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ Python >= 3.11 │ ✓ │ 3.11.5 │
│ Git installed │ ✓ │ /usr/bin/git │
│ Anthropic auth │ ✓ │ OAuth (logged in) │
│ Config file exists │ ✓ │ .quacking/config.toml │
│ .quacking directory │ ✓ │ ./.quacking │
│ pytest installed │ ✓ │ /usr/bin/pytest │
│ ruff installed │ ✓ │ /usr/bin/ruff │
└────────────────────────┴────────┴──────────────────────────────┘
All checks passed! Ready to run Quacking.
Quacking can run as a background daemon with a WebSocket API for IDE integrations and web-based monitoring interfaces.
# Start with defaults (localhost:8765)
quacking daemon
# Specify host and port
quacking daemon --host 0.0.0.0 --port 9000Output:
Starting Quacking daemon on ws://localhost:8765
Press Ctrl+C to stop
Daemon running on ws://localhost:8765
Connect to the daemon using any WebSocket client. All messages are JSON.
// Request
{"action": "status"}
// Response
{
"type": "status",
"data": {
"phase": "building",
"current_step": "step-003",
"steps_completed": 2,
"steps_total": 10,
"pending_escalations": 0,
"builder_busy": true
}
}// Pause
{"action": "pause"}
// Resume
{"action": "resume"}// Request
{"action": "escalations"}
// Response
{
"type": "escalations",
"data": [
{
"id": "ESC-001",
"type": "spec_conflict",
"urgency": "high",
"question": "Should authentication use JWT or sessions?",
"options": [
{"id": "opt-0", "label": "JWT"},
{"id": "opt-1", "label": "Sessions"}
]
}
]
}// Request
{
"action": "resolve",
"escalation_id": "ESC-001",
"decision": "opt-0",
"rationale": "JWT provides better scalability"
}The daemon broadcasts events to all connected clients:
// Step started
{"type": "event", "event": "step.started", "data": {"step_id": "step-003"}}
// Step completed
{"type": "event", "event": "step.completed", "data": {"step_id": "step-003", "verdict": "pass"}}
// Escalation created
{"type": "event", "event": "escalation.created", "data": {"id": "ESC-002", "urgency": "high"}}
// Project complete
{"type": "event", "event": "project.complete", "data": {"status": "complete", "steps_completed": 10}}import asyncio
import json
import websockets
async def monitor_quacking():
async with websockets.connect("ws://localhost:8765") as ws:
# Get initial status
await ws.send(json.dumps({"action": "status"}))
response = json.loads(await ws.recv())
print(f"Phase: {response['data']['phase']}")
# Listen for events
async for message in ws:
event = json.loads(message)
if event.get("type") == "event":
print(f"Event: {event['event']} - {event['data']}")
asyncio.run(monitor_quacking())const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
ws.send(JSON.stringify({ action: 'status' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'status') {
console.log(`Phase: ${data.data.phase}`);
} else if (data.type === 'event') {
console.log(`Event: ${data.event}`, data.data);
}
};See docs/websocket_protocol.md for the complete API specification.
Quacking is configured via .quacking/config.toml in your project.
[project]
id = "my-project"
name = "My Project"
[paths]
orchestrator_repo = ".quacking"
project_repo = "."
[models]
planning = "claude-opus-4-5"
builder = "claude-sonnet-4-5"
reviewer = "claude-opus-4-5"
spec_manager = "claude-sonnet-4-5"[agents.builder]
max_tokens_per_step = 50000
temperature = 0.7
max_retries = 3
[agents.reviewer]
temperature = 0.3
batch_size = 3
batch_timeout_seconds = 300CI/CD hooks and runners are configured during the planning phase for your specific project.
[ci]
pre_commit_timeout_seconds = 30
post_commit_timeout_seconds = 300
[[ci.pre_commit_hooks]]
name = "ruff-check"
command = "ruff check ."
blocking = true
timeout_seconds = 10
[[ci.pre_commit_hooks]]
name = "mypy"
command = "mypy src/"
blocking = true
timeout_seconds = 30
[[ci.post_commit_runners]]
name = "pytest"
command = "pytest --cov=src --cov-report=term -q"
blocking = true
timeout_seconds = 300
produces_coverage = true
[ci.coverage]
minimum_overall = 80.0
minimum_new_code = 90.0
fail_on_decrease = true[ci]
pre_commit_timeout_seconds = 30
post_commit_timeout_seconds = 300
[[ci.pre_commit_hooks]]
name = "eslint"
command = "npm run lint"
blocking = true
timeout_seconds = 30
[[ci.pre_commit_hooks]]
name = "typecheck"
command = "npm run typecheck"
blocking = true
timeout_seconds = 60
[[ci.post_commit_runners]]
name = "jest"
command = "npm test -- --coverage"
blocking = true
timeout_seconds = 300
produces_coverage = true
[ci.coverage]
minimum_overall = 80.0
minimum_new_code = 90.0
fail_on_decrease = true[notifications]
webhook_url = "https://hooks.slack.com/services/..."
notify_on = ["escalation.created", "project.complete", "step.failed"].quacking/
├── config.toml # Quacking configuration
├── projects/
│ └── {project-id}/
│ ├── state.json # Current orchestration state
│ ├── escalations/ # Pending escalations
│ └── metrics.db # SQLite metrics database
├── specs/
│ ├── canonical.md # Canonical specification
│ └── builder.md # Derived builder specification
└── history/
└── {project-id}.json # DAG history
src/
├── ... # Your project source code
# Run all tests
pytest
# Run with coverage
pytest --cov=src/quacking --cov-report=html
# Run specific test categories
pytest tests/unit/
pytest tests/integration/
pytest tests/regression/# Lint
ruff check src/
# Format
ruff format src/
# Type check
mypy src/flowchart TB
subgraph Planning["Planning Phase"]
Human([Human]) --> PlanningAgent[Planning Agent]
PlanningAgent --> CanonicalSpec[(Canonical Spec)]
PlanningAgent --> BuilderSpec[(Builder Spec)]
PlanningAgent --> BuildPlan[Build Plan]
end
subgraph BuildLoop["Build Loop"]
BuilderSpec --> Builder[Builder Agent]
BuildPlan --> Builder
Builder --> |implements| Code[Code Changes]
Code --> |commit| Git[Git Commit]
Git --> CI[CI/CD Manager]
CI --> |results| Reviewers
subgraph Reviewers["Review"]
CanonicalSpec --> CodeReviewer[Code Reviewer]
CanonicalSpec --> SpecReviewer[Spec Reviewer]
CodeReviewer --> Verdict{Verdict}
SpecReviewer --> Verdict
end
Verdict --> |pass| NextStep[Next Step]
Verdict --> |fail| SpecManager[Spec Manager]
SpecManager --> |feedback| Builder
SpecManager --> |updates| BuilderSpec
end
subgraph Escalations["Human Escalation"]
SpecManager -.-> |ambiguity| Human
Human -.-> |decision| SpecManager
end
NextStep --> |loop| Builder
NextStep --> |complete| Done([Project Complete])
MIT License - see LICENSE for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
- Issues: GitHub Issues
- Documentation: docs/
- WebSocket API: docs/websocket_protocol.md