devflow-toolkit 0.3.0__py3-none-any.whl
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.
- devflow/__init__.py +0 -0
- devflow/adapters/__init__.py +47 -0
- devflow/adapters/agents.py +49 -0
- devflow/adapters/base.py +81 -0
- devflow/adapters/claude_code.py +120 -0
- devflow/adapters/codex.py +111 -0
- devflow/adapters/detector.py +118 -0
- devflow/adapters/instructions.py +263 -0
- devflow/adapters/kiro.py +211 -0
- devflow/adapters/opencode.py +237 -0
- devflow/adapters/registry.py +41 -0
- devflow/cli.py +39 -0
- devflow/commands/__init__.py +6 -0
- devflow/commands/approve.py +98 -0
- devflow/commands/harness.py +98 -0
- devflow/commands/init.py +544 -0
- devflow/commands/spec.py +514 -0
- devflow/commands/status.py +156 -0
- devflow/core/__init__.py +15 -0
- devflow/core/architecture.py +469 -0
- devflow/core/artifacts/__init__.py +29 -0
- devflow/core/artifacts/errors.py +19 -0
- devflow/core/artifacts/models.py +82 -0
- devflow/core/artifacts/store.py +130 -0
- devflow/core/clock.py +67 -0
- devflow/core/config.py +706 -0
- devflow/core/constitution.py +166 -0
- devflow/core/discovery.py +1304 -0
- devflow/core/ports.py +159 -0
- devflow/core/profile_manager.py +311 -0
- devflow/core/project.py +533 -0
- devflow/core/spec_workflow.py +932 -0
- devflow/core/specification.py +2443 -0
- devflow/core/state/__init__.py +75 -0
- devflow/core/state/errors.py +39 -0
- devflow/core/state/events.py +725 -0
- devflow/core/state/locator.py +116 -0
- devflow/core/state/lock.py +69 -0
- devflow/core/state/manager.py +960 -0
- devflow/core/state/models.py +164 -0
- devflow/core/state/transitions.py +114 -0
- devflow/models/__init__.py +6 -0
- devflow/models/profile.py +63 -0
- devflow/models/project.py +47 -0
- devflow/profiles/ai-rag/constitution/ai-rag-standards.md +49 -0
- devflow/profiles/ai-rag/profile.yaml +28 -0
- devflow/profiles/base/constitution/architecture.md +58 -0
- devflow/profiles/base/constitution/code-standards.md +85 -0
- devflow/profiles/base/constitution/constitution.md +85 -0
- devflow/profiles/base/profile.yaml +15 -0
- devflow/profiles/django-backend/constitution/django-standards.md +64 -0
- devflow/profiles/django-backend/profile.yaml +24 -0
- devflow/profiles/fastapi-backend/constitution/fastapi-standards.md +59 -0
- devflow/profiles/fastapi-backend/profile.yaml +23 -0
- devflow/prompts/__init__.py +200 -0
- devflow/prompts/discovery.md +119 -0
- devflow/prompts/spec.greenfield.md +149 -0
- devflow/prompts/spec.md +116 -0
- devflow_toolkit-0.3.0.dist-info/METADATA +628 -0
- devflow_toolkit-0.3.0.dist-info/RECORD +63 -0
- devflow_toolkit-0.3.0.dist-info/WHEEL +4 -0
- devflow_toolkit-0.3.0.dist-info/entry_points.txt +2 -0
- devflow_toolkit-0.3.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Project Constitution
|
|
2
|
+
|
|
3
|
+
## 1. Purpose
|
|
4
|
+
|
|
5
|
+
This document defines the fundamental principles and
|
|
6
|
+
development standards that all AI agents must follow
|
|
7
|
+
when analyzing, planning, implementing or modifying
|
|
8
|
+
this project.
|
|
9
|
+
|
|
10
|
+
These principles apply to all development activities,
|
|
11
|
+
including new features, bug fixes, refactoring,
|
|
12
|
+
integrations and optimizations.
|
|
13
|
+
|
|
14
|
+
## 2. Existing Project First
|
|
15
|
+
|
|
16
|
+
- Always inspect the existing codebase before proposing
|
|
17
|
+
or implementing changes.
|
|
18
|
+
- Understand the relevant modules, dependencies,
|
|
19
|
+
architecture and existing business logic.
|
|
20
|
+
- Prefer extending existing components over creating
|
|
21
|
+
duplicated implementations.
|
|
22
|
+
- Preserve existing behavior unless the specification
|
|
23
|
+
explicitly requires changing it.
|
|
24
|
+
- Never assume that a feature must be implemented
|
|
25
|
+
from scratch.
|
|
26
|
+
|
|
27
|
+
## 3. Respect Existing Architecture
|
|
28
|
+
|
|
29
|
+
- Follow the established project architecture.
|
|
30
|
+
- Respect module boundaries and separation of concerns.
|
|
31
|
+
- Avoid introducing unnecessary dependencies.
|
|
32
|
+
- Avoid duplicating business logic.
|
|
33
|
+
- Do not introduce abstractions without a clear benefit.
|
|
34
|
+
- Consider the impact of changes on existing components.
|
|
35
|
+
|
|
36
|
+
## 4. Code Quality
|
|
37
|
+
|
|
38
|
+
- Follow the standards defined in code-standards.md.
|
|
39
|
+
- Follow the architectural principles defined in
|
|
40
|
+
architecture.md.
|
|
41
|
+
- Apply technology-specific standards when applicable.
|
|
42
|
+
|
|
43
|
+
## 5. Technology-Specific Standards
|
|
44
|
+
|
|
45
|
+
When the project includes a technology-specific profile,
|
|
46
|
+
follow the guidelines installed for that profile.
|
|
47
|
+
|
|
48
|
+
Examples include django-standards.md for Django projects
|
|
49
|
+
and fastapi-standards.md for FastAPI projects.
|
|
50
|
+
|
|
51
|
+
Technology-specific guidelines must only be applied
|
|
52
|
+
when the corresponding technology is present and its
|
|
53
|
+
profile is enabled for the project.
|
|
54
|
+
|
|
55
|
+
## 6. Change Safety
|
|
56
|
+
|
|
57
|
+
- Analyze potential regressions before modifying code.
|
|
58
|
+
- Preserve compatibility with existing integrations
|
|
59
|
+
unless otherwise specified.
|
|
60
|
+
- Consider error handling, edge cases and data integrity.
|
|
61
|
+
- Include or update automated tests when appropriate.
|
|
62
|
+
- Never silently discard existing functionality.
|
|
63
|
+
|
|
64
|
+
## 7. Specification Compliance
|
|
65
|
+
|
|
66
|
+
- Implement only what is required by the approved
|
|
67
|
+
specification.
|
|
68
|
+
- Respect the acceptance criteria.
|
|
69
|
+
- Identify ambiguities instead of inventing requirements.
|
|
70
|
+
- Report assumptions and relevant technical limitations.
|
|
71
|
+
|
|
72
|
+
## 8. Documentation
|
|
73
|
+
|
|
74
|
+
- Keep technical documentation consistent with the
|
|
75
|
+
actual implementation.
|
|
76
|
+
- Update documentation when a change affects existing
|
|
77
|
+
behavior, configuration or integrations.
|
|
78
|
+
|
|
79
|
+
## 9. Decision Making
|
|
80
|
+
|
|
81
|
+
- Prefer simple, maintainable solutions.
|
|
82
|
+
- Avoid over-engineering.
|
|
83
|
+
- Explain significant architectural decisions.
|
|
84
|
+
- Ask for clarification when a decision could
|
|
85
|
+
materially change the implementation.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: base
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Shared engineering standards for every DevFlow project.
|
|
4
|
+
|
|
5
|
+
detection:
|
|
6
|
+
files: []
|
|
7
|
+
dependencies: []
|
|
8
|
+
|
|
9
|
+
constitution:
|
|
10
|
+
- constitution.md
|
|
11
|
+
- code-standards.md
|
|
12
|
+
- architecture.md
|
|
13
|
+
|
|
14
|
+
templates: []
|
|
15
|
+
technologies: []
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Django Development Standards
|
|
2
|
+
|
|
3
|
+
## 1. Models
|
|
4
|
+
|
|
5
|
+
- Organize models into separate files when the domain
|
|
6
|
+
or model complexity justifies it.
|
|
7
|
+
- Use Meta classes to define ordering, indexes
|
|
8
|
+
and database constraints.
|
|
9
|
+
- Place model-related business logic in models
|
|
10
|
+
when appropriate.
|
|
11
|
+
- Avoid placing unrelated business logic in models.
|
|
12
|
+
- Use database constraints to enforce important
|
|
13
|
+
data integrity rules.
|
|
14
|
+
|
|
15
|
+
## 2. Views and API Endpoints
|
|
16
|
+
|
|
17
|
+
- Keep views thin and focused on HTTP responsibilities.
|
|
18
|
+
- Delegate complex business logic to services.
|
|
19
|
+
- Use class-based views for standard CRUD operations
|
|
20
|
+
when appropriate.
|
|
21
|
+
- Use function-based views for simple actions
|
|
22
|
+
when they provide better clarity.
|
|
23
|
+
- Validate incoming data using serializers
|
|
24
|
+
or appropriate validation components.
|
|
25
|
+
- Keep response handling consistent with the
|
|
26
|
+
existing API conventions.
|
|
27
|
+
|
|
28
|
+
## 3. Services
|
|
29
|
+
|
|
30
|
+
- Place complex business logic in a services/ package.
|
|
31
|
+
- Organize services around domain concepts.
|
|
32
|
+
- Keep services focused and cohesive.
|
|
33
|
+
- Prefer stateless services when possible.
|
|
34
|
+
- Avoid unnecessary service layers for simple operations.
|
|
35
|
+
|
|
36
|
+
## 4. Query Optimization
|
|
37
|
+
|
|
38
|
+
- Use select_related() for ForeignKey and OneToOneField
|
|
39
|
+
relationships.
|
|
40
|
+
- Use prefetch_related() for ManyToManyField
|
|
41
|
+
and reverse relationships.
|
|
42
|
+
- Use only() or defer() when partial field retrieval
|
|
43
|
+
provides a measurable benefit.
|
|
44
|
+
- Use exists() for boolean existence checks.
|
|
45
|
+
- Avoid N+1 queries.
|
|
46
|
+
- Inspect generated queries when performance
|
|
47
|
+
is a concern.
|
|
48
|
+
|
|
49
|
+
## 5. Transactions and Data Integrity
|
|
50
|
+
|
|
51
|
+
- Use transaction.atomic() when multiple database
|
|
52
|
+
operations must succeed or fail together.
|
|
53
|
+
- Handle integrity errors appropriately.
|
|
54
|
+
- Avoid unnecessary long-running transactions.
|
|
55
|
+
- Respect existing tenant and database isolation
|
|
56
|
+
mechanisms.
|
|
57
|
+
|
|
58
|
+
## 6. Testing
|
|
59
|
+
|
|
60
|
+
- Follow the project's existing testing conventions.
|
|
61
|
+
- Test successful operations and relevant failure cases.
|
|
62
|
+
- Cover permissions, validation and edge cases.
|
|
63
|
+
- Reuse existing factories, fixtures and test utilities.
|
|
64
|
+
- Avoid duplicating test setup unnecessarily.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: django-backend
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Django backend development profile.
|
|
4
|
+
|
|
5
|
+
detection:
|
|
6
|
+
files:
|
|
7
|
+
- manage.py
|
|
8
|
+
dependencies:
|
|
9
|
+
- django
|
|
10
|
+
- djangorestframework
|
|
11
|
+
indicators:
|
|
12
|
+
- manage.py
|
|
13
|
+
- settings.py
|
|
14
|
+
- urls.py
|
|
15
|
+
|
|
16
|
+
constitution:
|
|
17
|
+
- django-standards.md
|
|
18
|
+
|
|
19
|
+
templates: []
|
|
20
|
+
|
|
21
|
+
technologies:
|
|
22
|
+
- python
|
|
23
|
+
- django
|
|
24
|
+
- django-rest-framework
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# FastAPI Development Standards
|
|
2
|
+
|
|
3
|
+
## 1. Application Structure
|
|
4
|
+
|
|
5
|
+
- Keep application bootstrap and configuration in a
|
|
6
|
+
dedicated module.
|
|
7
|
+
- Group routes by domain using routers.
|
|
8
|
+
- Keep request handling, business logic and data access
|
|
9
|
+
separated.
|
|
10
|
+
- Reuse existing dependency injection patterns before
|
|
11
|
+
introducing new ones.
|
|
12
|
+
|
|
13
|
+
## 2. Routes and Schemas
|
|
14
|
+
|
|
15
|
+
- Keep route handlers focused on HTTP concerns.
|
|
16
|
+
- Declare explicit request and response models.
|
|
17
|
+
- Define response models and status codes explicitly.
|
|
18
|
+
- Keep error responses consistent with the existing API.
|
|
19
|
+
- Avoid exposing internal ORM models through the API.
|
|
20
|
+
|
|
21
|
+
## 3. Async and I/O
|
|
22
|
+
|
|
23
|
+
- Do not block the event loop with synchronous I/O.
|
|
24
|
+
- Use async database and HTTP clients consistently.
|
|
25
|
+
- Set timeouts on external calls.
|
|
26
|
+
- Propagate cancellation where appropriate.
|
|
27
|
+
- Avoid unnecessary concurrency and background tasks.
|
|
28
|
+
|
|
29
|
+
## 4. Dependencies and Services
|
|
30
|
+
|
|
31
|
+
- Use FastAPI dependencies for shared request concerns.
|
|
32
|
+
- Place business logic in services rather than routes.
|
|
33
|
+
- Keep services focused and testable.
|
|
34
|
+
- Reuse existing sessions, clients and configuration.
|
|
35
|
+
- Avoid hidden global state.
|
|
36
|
+
|
|
37
|
+
## 5. Data Access
|
|
38
|
+
|
|
39
|
+
- Scope database sessions to the request or unit of work.
|
|
40
|
+
- Avoid N+1 queries and unnecessary eager loading.
|
|
41
|
+
- Use transactions for operations that must be atomic.
|
|
42
|
+
- Retrieve only the data required by the endpoint.
|
|
43
|
+
- Handle integrity and not-found errors explicitly.
|
|
44
|
+
|
|
45
|
+
## 6. Validation and Security
|
|
46
|
+
|
|
47
|
+
- Validate input with typed schemas.
|
|
48
|
+
- Enforce authentication and authorization at the
|
|
49
|
+
appropriate layer.
|
|
50
|
+
- Do not trust client-provided identifiers or roles.
|
|
51
|
+
- Avoid leaking secrets or internal details in errors.
|
|
52
|
+
- Consider rate limits and payload size limits when relevant.
|
|
53
|
+
|
|
54
|
+
## 7. Testing
|
|
55
|
+
|
|
56
|
+
- Follow the existing test layout and fixtures.
|
|
57
|
+
- Test success, validation, permission and failure paths.
|
|
58
|
+
- Use dependency overrides rather than global mocks.
|
|
59
|
+
- Keep tests independent and deterministic.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: fastapi-backend
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: FastAPI backend development profile.
|
|
4
|
+
|
|
5
|
+
detection:
|
|
6
|
+
files: []
|
|
7
|
+
dependencies:
|
|
8
|
+
- fastapi
|
|
9
|
+
- uvicorn
|
|
10
|
+
indicators:
|
|
11
|
+
- main.py
|
|
12
|
+
- routers
|
|
13
|
+
- dependencies
|
|
14
|
+
|
|
15
|
+
constitution:
|
|
16
|
+
- fastapi-standards.md
|
|
17
|
+
|
|
18
|
+
templates: []
|
|
19
|
+
|
|
20
|
+
technologies:
|
|
21
|
+
- python
|
|
22
|
+
- fastapi
|
|
23
|
+
- async
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Loading and rendering of shared harness-independent prompts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from devflow.core.config import AgentPermissions
|
|
8
|
+
|
|
9
|
+
PROMPTS_ROOT = Path(__file__).resolve().parent
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PromptError(Exception):
|
|
13
|
+
"""Raised when a bundled prompt cannot be loaded."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_prompt(name: str) -> str:
|
|
17
|
+
"""Load a bundled prompt template by filename."""
|
|
18
|
+
path = PROMPTS_ROOT / name
|
|
19
|
+
try:
|
|
20
|
+
return path.read_text(encoding="utf-8")
|
|
21
|
+
except OSError as error:
|
|
22
|
+
msg = f"Could not read prompt template: {path}"
|
|
23
|
+
raise PromptError(msg) from error
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_spec_prompt(
|
|
27
|
+
*,
|
|
28
|
+
request: str,
|
|
29
|
+
project_name: str,
|
|
30
|
+
context_path: str,
|
|
31
|
+
spec_path: str,
|
|
32
|
+
constitution_paths: list[str],
|
|
33
|
+
harness_name: str,
|
|
34
|
+
execution_mode: str,
|
|
35
|
+
permissions: AgentPermissions,
|
|
36
|
+
project_mode: str = "existing",
|
|
37
|
+
architecture_path: str = "",
|
|
38
|
+
architecture_digest: str = "",
|
|
39
|
+
architecture_style: str = "",
|
|
40
|
+
discovery_path: str = "",
|
|
41
|
+
discovery_digest: str = "",
|
|
42
|
+
discovery_decisions: list[str] | None = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Render the shared specification prompt for any harness."""
|
|
45
|
+
template_name = (
|
|
46
|
+
"spec.greenfield.md"
|
|
47
|
+
if project_mode == "greenfield"
|
|
48
|
+
else "spec.md"
|
|
49
|
+
)
|
|
50
|
+
template = load_prompt(template_name)
|
|
51
|
+
mode_instructions = _mode_instructions(
|
|
52
|
+
execution_mode,
|
|
53
|
+
spec_path,
|
|
54
|
+
permissions,
|
|
55
|
+
)
|
|
56
|
+
architecture_note = ""
|
|
57
|
+
if architecture_path:
|
|
58
|
+
architecture_note = (
|
|
59
|
+
f"- Declared architecture manifest: `{architecture_path}`\n"
|
|
60
|
+
f"- Architecture digest: `{architecture_digest}`\n"
|
|
61
|
+
f"- Declared architecture style: {architecture_style}\n"
|
|
62
|
+
)
|
|
63
|
+
discovery_note = ""
|
|
64
|
+
if discovery_path:
|
|
65
|
+
discovery_note = (
|
|
66
|
+
f"- Discovery record: `{discovery_path}`\n"
|
|
67
|
+
f"- Discovery digest: `{discovery_digest}`\n"
|
|
68
|
+
)
|
|
69
|
+
for decision in discovery_decisions or []:
|
|
70
|
+
discovery_note += f"- Discovery decision: {decision}\n"
|
|
71
|
+
replacements = {
|
|
72
|
+
"request": request,
|
|
73
|
+
"project_name": project_name,
|
|
74
|
+
"context_path": context_path,
|
|
75
|
+
"spec_path": spec_path,
|
|
76
|
+
"constitution_paths": (
|
|
77
|
+
", ".join(f"`{path}`" for path in constitution_paths)
|
|
78
|
+
or "none"
|
|
79
|
+
),
|
|
80
|
+
"harness_name": harness_name,
|
|
81
|
+
"execution_mode": execution_mode,
|
|
82
|
+
"project_mode": project_mode,
|
|
83
|
+
"architecture_note": architecture_note,
|
|
84
|
+
"discovery_note": discovery_note,
|
|
85
|
+
"mode_instructions": mode_instructions,
|
|
86
|
+
"permission_summary": _permission_summary(permissions),
|
|
87
|
+
}
|
|
88
|
+
rendered = template
|
|
89
|
+
for key, value in replacements.items():
|
|
90
|
+
rendered = rendered.replace("{{" + key + "}}", value)
|
|
91
|
+
return rendered
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def build_discovery_prompt(
|
|
95
|
+
*,
|
|
96
|
+
request: str,
|
|
97
|
+
project_name: str,
|
|
98
|
+
context_path: str,
|
|
99
|
+
discovery_path: str,
|
|
100
|
+
harness_name: str,
|
|
101
|
+
execution_mode: str,
|
|
102
|
+
permissions: AgentPermissions,
|
|
103
|
+
) -> str:
|
|
104
|
+
"""Render the interactive discovery prompt for any harness."""
|
|
105
|
+
template = load_prompt("discovery.md")
|
|
106
|
+
replacements = {
|
|
107
|
+
"request": request,
|
|
108
|
+
"project_name": project_name,
|
|
109
|
+
"context_path": context_path,
|
|
110
|
+
"discovery_path": discovery_path,
|
|
111
|
+
"harness_name": harness_name,
|
|
112
|
+
"execution_mode": execution_mode,
|
|
113
|
+
"mode_instructions": _discovery_mode_instructions(
|
|
114
|
+
discovery_path,
|
|
115
|
+
execution_mode,
|
|
116
|
+
permissions,
|
|
117
|
+
),
|
|
118
|
+
"permission_summary": _permission_summary(permissions),
|
|
119
|
+
}
|
|
120
|
+
rendered = template
|
|
121
|
+
for key, value in replacements.items():
|
|
122
|
+
rendered = rendered.replace("{{" + key + "}}", value)
|
|
123
|
+
return rendered
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _discovery_mode_instructions(
|
|
127
|
+
discovery_path: str,
|
|
128
|
+
execution_mode: str,
|
|
129
|
+
permissions: AgentPermissions,
|
|
130
|
+
) -> str:
|
|
131
|
+
if execution_mode != "interactive":
|
|
132
|
+
return (
|
|
133
|
+
"Discovery is incomplete. Do not write a specification and do "
|
|
134
|
+
"not invent answers. Report the pending questions and stop."
|
|
135
|
+
)
|
|
136
|
+
if not permissions.allow_spec_write:
|
|
137
|
+
return (
|
|
138
|
+
"Discovery is incomplete, but artifact writes are disabled. Ask "
|
|
139
|
+
"the user for explicit answers and acceptance, then report them "
|
|
140
|
+
"verbatim. Do not write the specification."
|
|
141
|
+
)
|
|
142
|
+
return (
|
|
143
|
+
"You are running interactively. Read the discovery record and ask "
|
|
144
|
+
"the user only about pending blocking questions and proposed "
|
|
145
|
+
"assumptions. Record only explicit answers. Update the same "
|
|
146
|
+
f"`{discovery_path}` file in place, preserving every existing id, "
|
|
147
|
+
"category, blocking flag and question text. Set an answered "
|
|
148
|
+
"question to `status: answered` with `answer`, `answered_by: user` "
|
|
149
|
+
"and an ISO-8601 `answered_at` timestamp. Set an accepted "
|
|
150
|
+
"assumption to `status: accepted` with `accepted_by: user` and "
|
|
151
|
+
"`accepted_at`. Never accept an assumption on the user's behalf. "
|
|
152
|
+
"Never change the request, project_mode, spec_id or change. Do not "
|
|
153
|
+
"write or modify `spec.md` in this phase. When no pending blocking "
|
|
154
|
+
"question or unaccepted assumption remains, stop and report that "
|
|
155
|
+
"Discovery is complete."
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _mode_instructions(
|
|
160
|
+
execution_mode: str,
|
|
161
|
+
spec_path: str,
|
|
162
|
+
permissions: AgentPermissions,
|
|
163
|
+
) -> str:
|
|
164
|
+
if execution_mode == "interactive":
|
|
165
|
+
if permissions.allow_spec_write:
|
|
166
|
+
return (
|
|
167
|
+
"You are running interactively. Ask concise clarifying questions "
|
|
168
|
+
"whenever missing information would change requirements or "
|
|
169
|
+
"acceptance criteria. Resolve what you can with the user, then "
|
|
170
|
+
f"write the complete specification to `{spec_path}` using the "
|
|
171
|
+
"available file tools. Do not finish until that file exists and "
|
|
172
|
+
"contains the complete document."
|
|
173
|
+
)
|
|
174
|
+
return (
|
|
175
|
+
"You are running interactively, but specification writes are "
|
|
176
|
+
"disabled. Ask clarifying questions and return the complete "
|
|
177
|
+
"specification as your final message. DevFlow will record the "
|
|
178
|
+
"deterministic fallback specification."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
"You are running non-interactively. Do not ask the user questions "
|
|
183
|
+
"and do not write files. Put every unresolved question or assumption "
|
|
184
|
+
"in section 7. Return only the complete Markdown specification as "
|
|
185
|
+
"your final answer. DevFlow will validate it and write it to "
|
|
186
|
+
f"`{spec_path}`."
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _permission_summary(permissions: AgentPermissions) -> str:
|
|
191
|
+
def status(value: bool) -> str:
|
|
192
|
+
return "allowed" if value else "denied"
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
f"- Project read: {status(permissions.allow_project_read)}\n"
|
|
196
|
+
f"- Specification write: {status(permissions.allow_spec_write)}\n"
|
|
197
|
+
"- Source code changes: "
|
|
198
|
+
f"{status(permissions.allow_source_code_changes)}\n"
|
|
199
|
+
"- Source changes remain out of scope for specification generation."
|
|
200
|
+
)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# DevFlow Discovery Task
|
|
2
|
+
|
|
3
|
+
You are the discovery agent for the project `{{project_name}}`.
|
|
4
|
+
|
|
5
|
+
## Source of Truth
|
|
6
|
+
|
|
7
|
+
- Change request: {{request}}
|
|
8
|
+
- Static analysis context: `{{context_path}}`
|
|
9
|
+
- Discovery record: `{{discovery_path}}`
|
|
10
|
+
- Harness: {{harness_name}}
|
|
11
|
+
- Execution mode: {{execution_mode}}
|
|
12
|
+
|
|
13
|
+
Read the context and the discovery record before talking to the user.
|
|
14
|
+
The discovery record is the only place where answers and assumption
|
|
15
|
+
acceptance may be recorded.
|
|
16
|
+
|
|
17
|
+
## Purpose
|
|
18
|
+
|
|
19
|
+
Discovery decides whether the request is ready to become a
|
|
20
|
+
specification. It does not write the specification and it does not
|
|
21
|
+
change application code.
|
|
22
|
+
|
|
23
|
+
A specification may only be generated when:
|
|
24
|
+
|
|
25
|
+
- every question with `blocking: true` has an explicit answer; and
|
|
26
|
+
- every proposed assumption has been explicitly accepted.
|
|
27
|
+
|
|
28
|
+
Questions with `blocking: false` may remain pending. Never change a
|
|
29
|
+
question from blocking to non-blocking without a clear justification
|
|
30
|
+
based on user-visible behavior, data, security, integrations,
|
|
31
|
+
dependencies, deployment or architecture boundaries.
|
|
32
|
+
|
|
33
|
+
## Non-Negotiable Boundaries
|
|
34
|
+
|
|
35
|
+
- Do not write, overwrite or delete `spec.md`.
|
|
36
|
+
- Do not modify application source code, tests, configuration,
|
|
37
|
+
dependencies or the constitution.
|
|
38
|
+
- Do not invent answers. If the user is unsure, leave the question
|
|
39
|
+
pending and explain what decision is needed.
|
|
40
|
+
- Do not accept assumptions on the user's behalf. Acceptance is an
|
|
41
|
+
explicit human action.
|
|
42
|
+
- Preserve every existing id, question text, category, blocking flag,
|
|
43
|
+
option, request, `spec_id`, `change` and `project_mode`.
|
|
44
|
+
- Record only what the user explicitly said. Do not summarize away
|
|
45
|
+
details that change scope.
|
|
46
|
+
|
|
47
|
+
## Discovery Record Format
|
|
48
|
+
|
|
49
|
+
The file is YAML with this shape:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
version: 1
|
|
53
|
+
spec_id: "001"
|
|
54
|
+
change: "001-short-slug"
|
|
55
|
+
request: "Original request"
|
|
56
|
+
project_mode: existing
|
|
57
|
+
status: awaiting_clarification
|
|
58
|
+
created_at: "YYYY-MM-DDTHH:MM:SSZ"
|
|
59
|
+
updated_at: "YYYY-MM-DDTHH:MM:SSZ"
|
|
60
|
+
questions:
|
|
61
|
+
- id: Q1
|
|
62
|
+
category: functional_scope
|
|
63
|
+
question: "..."
|
|
64
|
+
reason: "..."
|
|
65
|
+
blocking: true
|
|
66
|
+
status: answered
|
|
67
|
+
options: []
|
|
68
|
+
answer: "..."
|
|
69
|
+
answered_by: user
|
|
70
|
+
answered_at: "YYYY-MM-DDTHH:MM:SSZ"
|
|
71
|
+
assumptions:
|
|
72
|
+
- id: A1
|
|
73
|
+
question_id: Q1
|
|
74
|
+
value: "..."
|
|
75
|
+
reason: "..."
|
|
76
|
+
source: agent_default
|
|
77
|
+
status: accepted
|
|
78
|
+
accepted_by: user
|
|
79
|
+
accepted_at: "YYYY-MM-DDTHH:MM:SSZ"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Valid question categories are `functional_scope`, `user_behavior`,
|
|
83
|
+
`data_persistence`, `security_authentication`,
|
|
84
|
+
`external_integration`, `architecture_boundary`, `dependencies` and
|
|
85
|
+
`deployment`.
|
|
86
|
+
|
|
87
|
+
Valid question statuses are `pending` and `answered`. Valid assumption
|
|
88
|
+
statuses are `pending_acceptance` and `accepted`.
|
|
89
|
+
|
|
90
|
+
An answered question requires `answer`, `answered_by` and
|
|
91
|
+
`answered_at`. An accepted assumption requires `accepted_by` and
|
|
92
|
+
`accepted_at`. A pending item must not contain those fields.
|
|
93
|
+
|
|
94
|
+
Update `updated_at` whenever the file changes. Set `status` to
|
|
95
|
+
`awaiting_clarification` while anything blocking or unaccepted
|
|
96
|
+
remains, and to `complete` only when nothing does.
|
|
97
|
+
|
|
98
|
+
## Conversation Rules
|
|
99
|
+
|
|
100
|
+
- Ask one focused question at a time.
|
|
101
|
+
- Explain why the answer changes the specification.
|
|
102
|
+
- Offer the recorded options when they exist, but accept a free-form
|
|
103
|
+
answer when it is clearer.
|
|
104
|
+
- For each proposed assumption, state the proposal and ask for
|
|
105
|
+
explicit acceptance or rejection. If rejected, ask what to do
|
|
106
|
+
instead.
|
|
107
|
+
- Stop asking once every blocking decision is resolved. Do not pad the
|
|
108
|
+
conversation with optional preferences.
|
|
109
|
+
|
|
110
|
+
## Execution Instructions
|
|
111
|
+
|
|
112
|
+
{{mode_instructions}}
|
|
113
|
+
|
|
114
|
+
## Permission Summary
|
|
115
|
+
|
|
116
|
+
{{permission_summary}}
|
|
117
|
+
|
|
118
|
+
Return a short report of what was answered, what was accepted and what
|
|
119
|
+
remains pending. Do not generate the specification.
|