project-workflow 0.9.0__tar.gz → 0.9.2__tar.gz
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.
- {project_workflow-0.9.0 → project_workflow-0.9.2}/CHANGELOG.md +40 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/MANIFEST.in +1 -1
- project_workflow-0.9.2/PKG-INFO +170 -0
- project_workflow-0.9.2/README.md +143 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/pyproject.toml +6 -4
- project_workflow-0.9.2/scripts/build_runtime_bundle.py +134 -0
- project_workflow-0.9.2/scripts/capture_architecture_snapshot.py +143 -0
- project_workflow-0.9.2/scripts/capture_compatibility_baseline.py +126 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/scripts/capture_dogfood_journey.py +3 -10
- project_workflow-0.9.2/scripts/capture_test_inventory.py +80 -0
- project_workflow-0.9.2/scripts/check_documentation.py +172 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/scripts/release_contract.py +22 -12
- {project_workflow-0.9.0 → project_workflow-0.9.2}/scripts/run_coordination_evaluations.py +10 -29
- {project_workflow-0.9.0 → project_workflow-0.9.2}/scripts/verify_package_journeys.py +69 -80
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/_version.py +1 -1
- project_workflow-0.9.2/src/project_workflow/adapter_common.py +181 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/claude_adapter.py +69 -53
- project_workflow-0.9.2/src/project_workflow/cli.py +1278 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/AGENTS.md +2 -2
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex_adapter.py +82 -179
- project_workflow-0.9.2/src/project_workflow/commands.py +3290 -0
- project_workflow-0.9.2/src/project_workflow/contracts.py +1461 -0
- project_workflow-0.9.2/src/project_workflow/coordination.py +3059 -0
- project_workflow-0.9.2/src/project_workflow/execution.py +2132 -0
- project_workflow-0.9.2/src/project_workflow/execution_config.py +540 -0
- project_workflow-0.9.2/src/project_workflow/inspection.py +3513 -0
- project_workflow-0.9.2/src/project_workflow/lifecycle.py +4654 -0
- project_workflow-0.9.2/src/project_workflow/maintenance.py +2274 -0
- project_workflow-0.9.2/src/project_workflow/orchestration.py +3100 -0
- project_workflow-0.9.2/src/project_workflow/repository.py +2144 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/templates/workflow.py +18855 -17800
- project_workflow-0.9.2/src/project_workflow.egg-info/PKG-INFO +170 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow.egg-info/SOURCES.txt +27 -1
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow.egg-info/requires.txt +2 -0
- project_workflow-0.9.2/tests/__init__.py +1 -0
- project_workflow-0.9.2/tests/test_architecture.py +163 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_claude_adapter.py +57 -20
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_codex_adapter.py +38 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_continuation_sufficiency.py +12 -6
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_coordination_controls.py +21 -16
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_coordination_evaluations.py +7 -22
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_coordinator_clarify_contract.py +2 -7
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_delegate_epic_mode.py +67 -36
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_delegate_host_assets.py +32 -36
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_delegate_task_mode.py +21 -36
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_delegation.py +35 -28
- project_workflow-0.9.2/tests/test_doctor_installation.py +712 -0
- project_workflow-0.9.2/tests/test_documentation.py +40 -0
- project_workflow-0.9.2/tests/test_epic_planning.py +721 -0
- project_workflow-0.9.2/tests/test_evidence_lifecycle.py +1292 -0
- project_workflow-0.9.2/tests/test_execution_configuration.py +433 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_execution_control_contract.py +4 -4
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_intent_behavioral_eval.py +18 -20
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_intent_integrity.py +5 -5
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_operational_status.py +14 -3
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_operational_status_actions.py +32 -11
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_operational_status_classification.py +8 -24
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_operational_status_cli.py +36 -51
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_operational_status_inspection.py +10 -13
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_package_journeys.py +5 -14
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_qa_release_control.py +11 -18
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_release_contract.py +15 -8
- project_workflow-0.9.2/tests/test_repository_upgrade.py +1413 -0
- project_workflow-0.9.2/tests/test_smoke_bomb.py +411 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_user_outcome_journey.py +27 -29
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_verification_campaign.py +19 -0
- project_workflow-0.9.2/tests/test_work_items.py +1227 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_workspace_mode.py +18 -21
- project_workflow-0.9.2/tests/workflow_test_support.py +409 -0
- project_workflow-0.9.0/PKG-INFO +0 -921
- project_workflow-0.9.0/README.md +0 -896
- project_workflow-0.9.0/src/project_workflow/cli.py +0 -25583
- project_workflow-0.9.0/src/project_workflow.egg-info/PKG-INFO +0 -921
- project_workflow-0.9.0/tests/test_doctor.py +0 -6085
- {project_workflow-0.9.0 → project_workflow-0.9.2}/LICENSE +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/README.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/output-schema.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-ANALYSIS.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-001/REPORT.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-001/baseline-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-001/baseline-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-001/candidate-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-001/candidate-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-002/REPORT.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-002/baseline-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-002/baseline-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-002/candidate-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-002/candidate-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-003/REPORT.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-003/candidate-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-003/candidate-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-004/REPORT.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-004/candidate-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-004/candidate-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-005/REPORT.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-005/candidate-trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/EPIC-016-run-005/candidate-trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/results/PROVENANCE-REDACTION.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/coordination/scenarios.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/REPORT.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/cases.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/continuation-cases.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/expectations.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/grade_results.py +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/output.schema.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/prompts.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/results/trial-1.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/results/trial-2.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/results/trial-3.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/evaluations/intent_integrity/runs.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/setup.cfg +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/__init__.py +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/claude_plugin/project-workflow-execution-control/.claude-plugin/plugin.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/claude_plugin/project-workflow-execution-control/README.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/claude_plugin/project-workflow-execution-control/hooks/hooks.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/claude_plugin/project-workflow-execution-control/scripts/project-workflow-claude-hook +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-backlog/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-clarify/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-constitution/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-coordinator/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-delegate/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-epic/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-fix/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-implement/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-planner/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-qa-review/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-requirements/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-retro/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-smoke-bomb/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex/skills/project-task/SKILL.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex_plugin/project-workflow-execution-control/.codex-plugin/plugin.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex_plugin/project-workflow-execution-control/README.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/codex_plugin/project-workflow-execution-control/scripts/project-workflow-codex-hook +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/cursor/rules/project-workflow.mdc +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Backlog.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Clarify.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Constitution.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Coordinator.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Delegate.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Epic.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Fix.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Implement.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Planner.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/QAReview.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Requirements.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Retro.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/SmokeBomb.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/prompts/Task.prompt.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow/templates/workflow +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow.egg-info/dependency_links.txt +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow.egg-info/entry_points.txt +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/src/project_workflow.egg-info/top_level.txt +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/BACKLOG.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/TRACKER.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/config.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/guidance.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/tasks/TASK-001-Historical-Work/EVIDENCE.json +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/tasks/TASK-001-Historical-Work/IMPLEMENTATION.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/.project-workflow/tasks/TASK-001-Historical-Work/REQUIREMENTS.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/fixtures/legacy-unversioned/USER-NOTES.md +0 -0
- {project_workflow-0.9.0 → project_workflow-0.9.2}/tests/test_coordination_subtraction.py +0 -0
|
@@ -4,6 +4,46 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.9.2 - 2026-08-31
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added public `project execution configure`, `status`, and `disable` commands so operators can
|
|
12
|
+
create and inspect exact host-neutral sealed authority without fabricating internal coordination
|
|
13
|
+
JSON or hashes. Successor envelopes retain previous controls and receipts.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Documented Codex installation as repository-local skills plus a package-owned ephemeral per-run
|
|
18
|
+
hook. A persistent marketplace-plugin listing is neither required nor treated as activation or
|
|
19
|
+
runtime proof.
|
|
20
|
+
|
|
21
|
+
### Known proof boundary
|
|
22
|
+
|
|
23
|
+
- Sealed runtime execution is certified for Codex only in this release. The Claude Code adapter and
|
|
24
|
+
managed assets remain packaged and fail closed, but no real authenticated Claude Code canary has
|
|
25
|
+
passed; this release makes no Claude runtime or dual-host certification claim.
|
|
26
|
+
|
|
27
|
+
## 0.9.1 - 2026-08-29
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Replaced the authored 25,583-line CLI monolith with cohesive, acyclic runtime domains, a bounded
|
|
32
|
+
compatibility facade, and one deterministic manifest-driven standalone runtime without changing
|
|
33
|
+
the public v0.9 command or schema contract.
|
|
34
|
+
- Split the catch-all Doctor tests into product-boundary suites, centralized only shared fixtures,
|
|
35
|
+
and made locked Ruff, Ruff format, mypy, architecture, documentation, full-suite, and package
|
|
36
|
+
journey checks part of both CI and release validation.
|
|
37
|
+
- Replaced the oversized README and stale release guidance with a small authority-led documentation
|
|
38
|
+
hierarchy covering architecture, use, contribution, maintenance, and release ownership.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Kept a completed Task or Epic's retained verification campaign inspectable from terminal global
|
|
43
|
+
tracker state so Doctor and delivery projection do not lose exact-candidate proof after closeout.
|
|
44
|
+
- Removed dead distribution globs and stale current-version guidance while retaining historical
|
|
45
|
+
workflow records, exact release artifacts, blocked proof obligations, and unique work.
|
|
46
|
+
|
|
7
47
|
## 0.9.0 - 2026-08-29
|
|
8
48
|
|
|
9
49
|
### Added
|
|
@@ -5,4 +5,4 @@ recursive-include scripts *.py
|
|
|
5
5
|
recursive-include tests *.py
|
|
6
6
|
recursive-include tests/fixtures *
|
|
7
7
|
recursive-include evaluations/intent_integrity *.json *.md *.py
|
|
8
|
-
recursive-include evaluations/coordination *.json *.md
|
|
8
|
+
recursive-include evaluations/coordination *.json *.md
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: project-workflow
|
|
3
|
+
Version: 0.9.2
|
|
4
|
+
Summary: Spec-driven development with GitHub Copilot, Claude Code, OpenAI Codex, and Cursor: workflow scaffolding, QA review, retro, and task management CLI
|
|
5
|
+
Author-email: John Detlefs <john@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/johndetlefs/project-workflow
|
|
8
|
+
Project-URL: Repository, https://github.com/johndetlefs/project-workflow.git
|
|
9
|
+
Project-URL: Issues, https://github.com/johndetlefs/project-workflow/issues
|
|
10
|
+
Keywords: workflow,spec-driven,ai,github-copilot,claude-code,codex,cursor,task-management
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
22
|
+
Requires-Dist: mypy>=1.15; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: ruff>=0.11; extra == "dev"
|
|
25
|
+
Requires-Dist: setuptools>=65.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# project-workflow
|
|
29
|
+
|
|
30
|
+
Project Workflow is a repository-native delivery system for turning owner intent into planned,
|
|
31
|
+
implemented, evidenced, reviewed work. Its state is plain Markdown and JSON beside the code, so
|
|
32
|
+
people and coding agents can inspect the same requirements, status, decisions, and proof.
|
|
33
|
+
|
|
34
|
+
Its repository guidance supports GitHub Copilot, Claude Code, OpenAI Codex, and Cursor. Sealed
|
|
35
|
+
runtime enforcement has a narrower, versioned proof boundary: v0.9.2 is runtime-certified for
|
|
36
|
+
Codex only. The packaged Claude Code adapter remains fail-closed and uncertified until its real
|
|
37
|
+
authenticated host canary passes; Cursor and GitHub Copilot are not sealed-runtime targets. Project
|
|
38
|
+
Workflow complements issue trackers, Git hosts, CI, registries, and deployment platforms; it does
|
|
39
|
+
not replace their authority.
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
From the root of an existing Git repository:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uvx --from project-workflow==0.9.2 project init --agent codex
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Choose `github-copilot`, `claude-code`, `codex`, or `cursor` to match the agent that will operate
|
|
50
|
+
the repository. For an existing installation, use upgrade—not init:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uvx --from project-workflow==0.9.2 project upgrade --agent codex
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then describe the outcome in ordinary language. The installed guidance routes it to the smallest
|
|
57
|
+
sufficient record:
|
|
58
|
+
|
|
59
|
+
| Route | Use it for | Durable record |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| Backlog | Optional future intent not ready for execution | `BL-*` row in `BACKLOG.md` |
|
|
62
|
+
| Fix | One bounded correction to a delivered or accepted baseline | `FIX-*` folder and global tracker row |
|
|
63
|
+
| Task | One new independently reviewable outcome | `TASK-*` requirements and implementation |
|
|
64
|
+
| Epic | Coordinated workstreams with shared parent outcomes | `EPIC-*` contract, decomposition, children, audit, and retro |
|
|
65
|
+
|
|
66
|
+
An in-scope correction stays in its active work item. Completed history is not rewritten to make a
|
|
67
|
+
later defect look original.
|
|
68
|
+
|
|
69
|
+
## See What Is True
|
|
70
|
+
|
|
71
|
+
Start with the read-only status projection:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
./.project-workflow/cli/workflow status
|
|
75
|
+
./.project-workflow/cli/workflow status --id TASK-001
|
|
76
|
+
./.project-workflow/cli/workflow status --strict
|
|
77
|
+
./.project-workflow/cli/workflow status --format json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Status reports sourced lifecycle, proof, blockers, delivery state, and the next safe action. It
|
|
81
|
+
does not execute that action. Use Doctor for workflow diagnosis:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
./.project-workflow/cli/workflow doctor
|
|
85
|
+
./.project-workflow/cli/workflow doctor --strict
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Tests, a passing Doctor, `Complete`, merge, release, deployment, adoption, and owner acceptance are
|
|
89
|
+
separate evidence layers. Project Workflow reports the strongest layer actually proved.
|
|
90
|
+
|
|
91
|
+
## How Work Moves
|
|
92
|
+
|
|
93
|
+
The owner confirms the plain-language Intent and outcome boundary once. The Coordinator then plans,
|
|
94
|
+
clarifies, implements, validates, and commissions QA autonomously inside that approved envelope.
|
|
95
|
+
Material drift, missing authority, or a changed proof obligation returns to the owner.
|
|
96
|
+
|
|
97
|
+
The normal Task path is:
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
Analysing -> Ready -> In Progress -> Testing -> Review -> Complete
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Epics use the same outcome discipline plus a contract, authoritative decomposition, child tracker,
|
|
104
|
+
intent audit, parent acceptance map, closeout audit, and retro. Fixes stay deliberately lighter.
|
|
105
|
+
|
|
106
|
+
For detailed commands and examples, read [Using Project Workflow](docs/using-project-workflow.md)
|
|
107
|
+
or run `./.project-workflow/cli/workflow --help`.
|
|
108
|
+
|
|
109
|
+
Approved material work can optionally use [Sealed Host Execution](docs/execution-control.md). Codex
|
|
110
|
+
uses repository-local skills plus an ephemeral per-run hook; a permanent marketplace-plugin entry
|
|
111
|
+
is neither required nor accepted as activation proof.
|
|
112
|
+
|
|
113
|
+
## What Is Installed
|
|
114
|
+
|
|
115
|
+
Initialization creates:
|
|
116
|
+
|
|
117
|
+
- `.project-workflow/` configuration, manifest, backlog, trackers, tasks, guidance, and a
|
|
118
|
+
dependency-free local CLI;
|
|
119
|
+
- host-specific agent guidance for the selected mode;
|
|
120
|
+
- managed instruction blocks that point the agent at repository-local workflow truth.
|
|
121
|
+
|
|
122
|
+
Tracked requirements, plans, approvals, evidence, and local guidance remain repository-owned.
|
|
123
|
+
Managed helpers and installed host assets are generated derivatives; update their canonical source
|
|
124
|
+
or use the supported generator/upgrade path instead of editing copies.
|
|
125
|
+
|
|
126
|
+
See [Documentation and Source Authority](docs/authority.md) for the complete hierarchy and
|
|
127
|
+
[Compatibility](COMPATIBILITY.md) for versioned repository support.
|
|
128
|
+
|
|
129
|
+
## Contributing
|
|
130
|
+
|
|
131
|
+
Project Workflow is one Python package, one public `project` command, and one generated
|
|
132
|
+
dependency-free helper. Canonical runtime code is split by domain under `src/project_workflow/`;
|
|
133
|
+
`src/project_workflow/templates/workflow.py` and `.project-workflow/cli/workflow.py` are generated.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
uv sync --locked --extra dev
|
|
137
|
+
uv run --locked ruff check src/project_workflow/*.py scripts tests
|
|
138
|
+
uv run --locked ruff format --check src/project_workflow/*.py scripts tests
|
|
139
|
+
uv run --locked mypy src/project_workflow/*.py
|
|
140
|
+
PATH="/opt/homebrew/bin:$PATH" uv run --locked pytest -q
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Read [Contributing](docs/contributing.md) before changing source and
|
|
144
|
+
[Architecture](docs/architecture.md) before moving responsibilities. Maintainers should also read
|
|
145
|
+
[Maintenance](docs/maintenance.md); public release authority is isolated in
|
|
146
|
+
[RELEASING.md](RELEASING.md).
|
|
147
|
+
|
|
148
|
+
## Documentation Map
|
|
149
|
+
|
|
150
|
+
| Need | Authority |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| Product mission and stable outcomes | [Constitution](.project-workflow/CONSTITUTION.md) |
|
|
153
|
+
| Repository operating rules | [AGENTS.md](AGENTS.md) and [local guidance](.project-workflow/guidance.md) |
|
|
154
|
+
| Orientation and first commands | This README |
|
|
155
|
+
| Work-item operation | [Using Project Workflow](docs/using-project-workflow.md) |
|
|
156
|
+
| Codex-certified sealed execution and Claude Code limitations | [Sealed Host Execution](docs/execution-control.md) |
|
|
157
|
+
| Source boundaries and generated ownership | [Architecture](docs/architecture.md) |
|
|
158
|
+
| Development and validation | [Contributing](docs/contributing.md) |
|
|
159
|
+
| Upgrade, hygiene, and generated assets | [Maintenance](docs/maintenance.md) |
|
|
160
|
+
| Compatibility policy | [COMPATIBILITY.md](COMPATIBILITY.md) |
|
|
161
|
+
| Public release procedure | [RELEASING.md](RELEASING.md) |
|
|
162
|
+
| Current command syntax | `project --help` and the [local CLI guide](.project-workflow/cli/README.md) |
|
|
163
|
+
|
|
164
|
+
Workflow task folders are durable state and audit history, not competing current product
|
|
165
|
+
instructions.
|
|
166
|
+
|
|
167
|
+
## License And Support
|
|
168
|
+
|
|
169
|
+
Project Workflow is available under the [MIT License](LICENSE). Report defects and proposals through
|
|
170
|
+
[GitHub Issues](https://github.com/johndetlefs/project-workflow/issues).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# project-workflow
|
|
2
|
+
|
|
3
|
+
Project Workflow is a repository-native delivery system for turning owner intent into planned,
|
|
4
|
+
implemented, evidenced, reviewed work. Its state is plain Markdown and JSON beside the code, so
|
|
5
|
+
people and coding agents can inspect the same requirements, status, decisions, and proof.
|
|
6
|
+
|
|
7
|
+
Its repository guidance supports GitHub Copilot, Claude Code, OpenAI Codex, and Cursor. Sealed
|
|
8
|
+
runtime enforcement has a narrower, versioned proof boundary: v0.9.2 is runtime-certified for
|
|
9
|
+
Codex only. The packaged Claude Code adapter remains fail-closed and uncertified until its real
|
|
10
|
+
authenticated host canary passes; Cursor and GitHub Copilot are not sealed-runtime targets. Project
|
|
11
|
+
Workflow complements issue trackers, Git hosts, CI, registries, and deployment platforms; it does
|
|
12
|
+
not replace their authority.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
From the root of an existing Git repository:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uvx --from project-workflow==0.9.2 project init --agent codex
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Choose `github-copilot`, `claude-code`, `codex`, or `cursor` to match the agent that will operate
|
|
23
|
+
the repository. For an existing installation, use upgrade—not init:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uvx --from project-workflow==0.9.2 project upgrade --agent codex
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then describe the outcome in ordinary language. The installed guidance routes it to the smallest
|
|
30
|
+
sufficient record:
|
|
31
|
+
|
|
32
|
+
| Route | Use it for | Durable record |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Backlog | Optional future intent not ready for execution | `BL-*` row in `BACKLOG.md` |
|
|
35
|
+
| Fix | One bounded correction to a delivered or accepted baseline | `FIX-*` folder and global tracker row |
|
|
36
|
+
| Task | One new independently reviewable outcome | `TASK-*` requirements and implementation |
|
|
37
|
+
| Epic | Coordinated workstreams with shared parent outcomes | `EPIC-*` contract, decomposition, children, audit, and retro |
|
|
38
|
+
|
|
39
|
+
An in-scope correction stays in its active work item. Completed history is not rewritten to make a
|
|
40
|
+
later defect look original.
|
|
41
|
+
|
|
42
|
+
## See What Is True
|
|
43
|
+
|
|
44
|
+
Start with the read-only status projection:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
./.project-workflow/cli/workflow status
|
|
48
|
+
./.project-workflow/cli/workflow status --id TASK-001
|
|
49
|
+
./.project-workflow/cli/workflow status --strict
|
|
50
|
+
./.project-workflow/cli/workflow status --format json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Status reports sourced lifecycle, proof, blockers, delivery state, and the next safe action. It
|
|
54
|
+
does not execute that action. Use Doctor for workflow diagnosis:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
./.project-workflow/cli/workflow doctor
|
|
58
|
+
./.project-workflow/cli/workflow doctor --strict
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Tests, a passing Doctor, `Complete`, merge, release, deployment, adoption, and owner acceptance are
|
|
62
|
+
separate evidence layers. Project Workflow reports the strongest layer actually proved.
|
|
63
|
+
|
|
64
|
+
## How Work Moves
|
|
65
|
+
|
|
66
|
+
The owner confirms the plain-language Intent and outcome boundary once. The Coordinator then plans,
|
|
67
|
+
clarifies, implements, validates, and commissions QA autonomously inside that approved envelope.
|
|
68
|
+
Material drift, missing authority, or a changed proof obligation returns to the owner.
|
|
69
|
+
|
|
70
|
+
The normal Task path is:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
Analysing -> Ready -> In Progress -> Testing -> Review -> Complete
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Epics use the same outcome discipline plus a contract, authoritative decomposition, child tracker,
|
|
77
|
+
intent audit, parent acceptance map, closeout audit, and retro. Fixes stay deliberately lighter.
|
|
78
|
+
|
|
79
|
+
For detailed commands and examples, read [Using Project Workflow](docs/using-project-workflow.md)
|
|
80
|
+
or run `./.project-workflow/cli/workflow --help`.
|
|
81
|
+
|
|
82
|
+
Approved material work can optionally use [Sealed Host Execution](docs/execution-control.md). Codex
|
|
83
|
+
uses repository-local skills plus an ephemeral per-run hook; a permanent marketplace-plugin entry
|
|
84
|
+
is neither required nor accepted as activation proof.
|
|
85
|
+
|
|
86
|
+
## What Is Installed
|
|
87
|
+
|
|
88
|
+
Initialization creates:
|
|
89
|
+
|
|
90
|
+
- `.project-workflow/` configuration, manifest, backlog, trackers, tasks, guidance, and a
|
|
91
|
+
dependency-free local CLI;
|
|
92
|
+
- host-specific agent guidance for the selected mode;
|
|
93
|
+
- managed instruction blocks that point the agent at repository-local workflow truth.
|
|
94
|
+
|
|
95
|
+
Tracked requirements, plans, approvals, evidence, and local guidance remain repository-owned.
|
|
96
|
+
Managed helpers and installed host assets are generated derivatives; update their canonical source
|
|
97
|
+
or use the supported generator/upgrade path instead of editing copies.
|
|
98
|
+
|
|
99
|
+
See [Documentation and Source Authority](docs/authority.md) for the complete hierarchy and
|
|
100
|
+
[Compatibility](COMPATIBILITY.md) for versioned repository support.
|
|
101
|
+
|
|
102
|
+
## Contributing
|
|
103
|
+
|
|
104
|
+
Project Workflow is one Python package, one public `project` command, and one generated
|
|
105
|
+
dependency-free helper. Canonical runtime code is split by domain under `src/project_workflow/`;
|
|
106
|
+
`src/project_workflow/templates/workflow.py` and `.project-workflow/cli/workflow.py` are generated.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv sync --locked --extra dev
|
|
110
|
+
uv run --locked ruff check src/project_workflow/*.py scripts tests
|
|
111
|
+
uv run --locked ruff format --check src/project_workflow/*.py scripts tests
|
|
112
|
+
uv run --locked mypy src/project_workflow/*.py
|
|
113
|
+
PATH="/opt/homebrew/bin:$PATH" uv run --locked pytest -q
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Read [Contributing](docs/contributing.md) before changing source and
|
|
117
|
+
[Architecture](docs/architecture.md) before moving responsibilities. Maintainers should also read
|
|
118
|
+
[Maintenance](docs/maintenance.md); public release authority is isolated in
|
|
119
|
+
[RELEASING.md](RELEASING.md).
|
|
120
|
+
|
|
121
|
+
## Documentation Map
|
|
122
|
+
|
|
123
|
+
| Need | Authority |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| Product mission and stable outcomes | [Constitution](.project-workflow/CONSTITUTION.md) |
|
|
126
|
+
| Repository operating rules | [AGENTS.md](AGENTS.md) and [local guidance](.project-workflow/guidance.md) |
|
|
127
|
+
| Orientation and first commands | This README |
|
|
128
|
+
| Work-item operation | [Using Project Workflow](docs/using-project-workflow.md) |
|
|
129
|
+
| Codex-certified sealed execution and Claude Code limitations | [Sealed Host Execution](docs/execution-control.md) |
|
|
130
|
+
| Source boundaries and generated ownership | [Architecture](docs/architecture.md) |
|
|
131
|
+
| Development and validation | [Contributing](docs/contributing.md) |
|
|
132
|
+
| Upgrade, hygiene, and generated assets | [Maintenance](docs/maintenance.md) |
|
|
133
|
+
| Compatibility policy | [COMPATIBILITY.md](COMPATIBILITY.md) |
|
|
134
|
+
| Public release procedure | [RELEASING.md](RELEASING.md) |
|
|
135
|
+
| Current command syntax | `project --help` and the [local CLI guide](.project-workflow/cli/README.md) |
|
|
136
|
+
|
|
137
|
+
Workflow task folders are durable state and audit history, not competing current product
|
|
138
|
+
instructions.
|
|
139
|
+
|
|
140
|
+
## License And Support
|
|
141
|
+
|
|
142
|
+
Project Workflow is available under the [MIT License](LICENSE). Report defects and proposals through
|
|
143
|
+
[GitHub Issues](https://github.com/johndetlefs/project-workflow/issues).
|
|
@@ -30,7 +30,9 @@ Issues = "https://github.com/johndetlefs/project-workflow/issues"
|
|
|
30
30
|
[project.optional-dependencies]
|
|
31
31
|
dev = [
|
|
32
32
|
"build>=1.2",
|
|
33
|
+
"mypy>=1.15",
|
|
33
34
|
"pytest>=7.0",
|
|
35
|
+
"ruff>=0.11",
|
|
34
36
|
"setuptools>=65.0",
|
|
35
37
|
]
|
|
36
38
|
|
|
@@ -64,15 +66,14 @@ project_workflow = [
|
|
|
64
66
|
"cursor/rules/*.mdc",
|
|
65
67
|
]
|
|
66
68
|
|
|
67
|
-
[tool.black]
|
|
68
|
-
line-length = 100
|
|
69
|
-
target-version = ["py310"]
|
|
70
|
-
|
|
71
69
|
[tool.ruff]
|
|
72
70
|
line-length = 100
|
|
73
71
|
target-version = "py310"
|
|
74
72
|
|
|
75
73
|
[tool.ruff.lint]
|
|
74
|
+
ignore = [
|
|
75
|
+
"E501", # The formatter is the line-layout authority; exact fixture strings may exceed it.
|
|
76
|
+
]
|
|
76
77
|
select = [
|
|
77
78
|
"E", # pycodestyle errors
|
|
78
79
|
"W", # pycodestyle warnings
|
|
@@ -86,6 +87,7 @@ python_version = "3.10"
|
|
|
86
87
|
warn_return_any = true
|
|
87
88
|
warn_unused_configs = true
|
|
88
89
|
disallow_untyped_defs = false
|
|
90
|
+
exclude = ["src/project_workflow/templates/"]
|
|
89
91
|
|
|
90
92
|
[tool.pytest.ini_options]
|
|
91
93
|
testpaths = ["tests"]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Build the dependency-free repository-local workflow runtime deterministically."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import ast
|
|
8
|
+
import hashlib
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
13
|
+
MANIFEST = ROOT / "scripts/runtime-modules.txt"
|
|
14
|
+
TEMPLATE = ROOT / "src/project_workflow/templates/workflow.py"
|
|
15
|
+
SOURCE_MIRROR = ROOT / ".project-workflow/cli/workflow.py"
|
|
16
|
+
GENERATED_MARKER = "# project-workflow:generated"
|
|
17
|
+
PROVENANCE = "# source-manifest: scripts/runtime-modules.txt"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def manifest_paths() -> tuple[Path, ...]:
|
|
21
|
+
entries = []
|
|
22
|
+
for raw in MANIFEST.read_text(encoding="utf-8").splitlines():
|
|
23
|
+
value = raw.strip()
|
|
24
|
+
if not value or value.startswith("#"):
|
|
25
|
+
continue
|
|
26
|
+
path = ROOT / value
|
|
27
|
+
if not path.is_file():
|
|
28
|
+
raise ValueError(f"Runtime manifest entry does not exist: {value}")
|
|
29
|
+
entries.append(path)
|
|
30
|
+
if not entries:
|
|
31
|
+
raise ValueError("Runtime manifest must contain at least one source module.")
|
|
32
|
+
return tuple(entries)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _top_level_removals(source: str) -> set[int]:
|
|
36
|
+
tree = ast.parse(source)
|
|
37
|
+
removals: set[int] = set()
|
|
38
|
+
for index, node in enumerate(tree.body):
|
|
39
|
+
remove = False
|
|
40
|
+
if (
|
|
41
|
+
index == 0
|
|
42
|
+
and isinstance(node, ast.Expr)
|
|
43
|
+
and isinstance(node.value, ast.Constant)
|
|
44
|
+
and isinstance(node.value.value, str)
|
|
45
|
+
):
|
|
46
|
+
remove = True
|
|
47
|
+
elif isinstance(node, ast.ImportFrom) and node.module == "__future__":
|
|
48
|
+
remove = True
|
|
49
|
+
elif isinstance(node, ast.ImportFrom) and (
|
|
50
|
+
node.level > 0 or (node.module or "").startswith("project_workflow")
|
|
51
|
+
):
|
|
52
|
+
remove = True
|
|
53
|
+
if remove:
|
|
54
|
+
removals.update(range(node.lineno, node.end_lineno + 1))
|
|
55
|
+
return removals
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def canonical_module_text(path: Path) -> str:
|
|
59
|
+
source = path.read_text(encoding="utf-8")
|
|
60
|
+
removals = _top_level_removals(source)
|
|
61
|
+
lines = source.splitlines()
|
|
62
|
+
kept = [
|
|
63
|
+
line
|
|
64
|
+
for number, line in enumerate(lines, start=1)
|
|
65
|
+
if number not in removals and not (number == 1 and line.startswith("#!"))
|
|
66
|
+
]
|
|
67
|
+
while kept and not kept[0].strip():
|
|
68
|
+
kept.pop(0)
|
|
69
|
+
while kept and not kept[-1].strip():
|
|
70
|
+
kept.pop()
|
|
71
|
+
return "\n".join(kept) + "\n"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def build_bundle() -> str:
|
|
75
|
+
paths = manifest_paths()
|
|
76
|
+
manifest_hash = hashlib.sha256(MANIFEST.read_bytes()).hexdigest()
|
|
77
|
+
sections = [
|
|
78
|
+
"#!/usr/bin/env python3\n",
|
|
79
|
+
'"""Generated dependency-free Project Workflow runtime. Do not edit directly."""\n',
|
|
80
|
+
"from __future__ import annotations\n\n",
|
|
81
|
+
f"{GENERATED_MARKER}\n",
|
|
82
|
+
f"{PROVENANCE}\n",
|
|
83
|
+
f"# manifest-sha256: {manifest_hash}\n\n",
|
|
84
|
+
]
|
|
85
|
+
for path in paths:
|
|
86
|
+
relative = path.relative_to(ROOT).as_posix()
|
|
87
|
+
sections.append(f"# --- begin {relative} ---\n")
|
|
88
|
+
sections.append(canonical_module_text(path))
|
|
89
|
+
sections.append(f"# --- end {relative} ---\n\n")
|
|
90
|
+
return "".join(sections).rstrip("\n") + "\n"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def expected_outputs() -> tuple[Path, Path]:
|
|
94
|
+
return TEMPLATE, SOURCE_MIRROR
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def check() -> int:
|
|
98
|
+
expected = build_bundle()
|
|
99
|
+
stale = [
|
|
100
|
+
path.relative_to(ROOT).as_posix()
|
|
101
|
+
for path in expected_outputs()
|
|
102
|
+
if not path.is_file() or path.read_text(encoding="utf-8") != expected
|
|
103
|
+
]
|
|
104
|
+
if stale:
|
|
105
|
+
print("Generated runtime is stale:")
|
|
106
|
+
for path in stale:
|
|
107
|
+
print(f"- {path}")
|
|
108
|
+
return 1
|
|
109
|
+
print("Generated runtime is current.")
|
|
110
|
+
return 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def write() -> int:
|
|
114
|
+
content = build_bundle()
|
|
115
|
+
for path in expected_outputs():
|
|
116
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
path.write_text(content, encoding="utf-8")
|
|
118
|
+
SOURCE_MIRROR.chmod(SOURCE_MIRROR.stat().st_mode | 0o111)
|
|
119
|
+
print(f"Wrote {TEMPLATE.relative_to(ROOT)}")
|
|
120
|
+
print(f"Wrote {SOURCE_MIRROR.relative_to(ROOT)}")
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def main() -> int:
|
|
125
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
126
|
+
mode = parser.add_mutually_exclusive_group(required=True)
|
|
127
|
+
mode.add_argument("--check", action="store_true")
|
|
128
|
+
mode.add_argument("--write", action="store_true")
|
|
129
|
+
args = parser.parse_args()
|
|
130
|
+
return check() if args.check else write()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
sys.exit(main())
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Capture canonical module and adapter ownership evidence as deterministic JSON."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import ast
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
13
|
+
MANIFEST = ROOT / "scripts/runtime-modules.txt"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def sha256(path: Path) -> str:
|
|
17
|
+
return "sha256:" + hashlib.sha256(path.read_bytes()).hexdigest()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def runtime_paths() -> list[Path]:
|
|
21
|
+
return [
|
|
22
|
+
ROOT / line.strip()
|
|
23
|
+
for line in MANIFEST.read_text(encoding="utf-8").splitlines()
|
|
24
|
+
if line.strip() and not line.lstrip().startswith("#")
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def internal_dependencies(path: Path, names: set[str]) -> list[str]:
|
|
29
|
+
dependencies: set[str] = set()
|
|
30
|
+
for node in ast.walk(ast.parse(path.read_text(encoding="utf-8"))):
|
|
31
|
+
if isinstance(node, ast.ImportFrom):
|
|
32
|
+
if node.level and node.module:
|
|
33
|
+
dependency = node.module.split(".", 1)[0]
|
|
34
|
+
if dependency in names:
|
|
35
|
+
dependencies.add(dependency)
|
|
36
|
+
elif (node.module or "").startswith("project_workflow."):
|
|
37
|
+
dependency = (node.module or "").split(".")[1]
|
|
38
|
+
if dependency in names:
|
|
39
|
+
dependencies.add(dependency)
|
|
40
|
+
elif isinstance(node, ast.Import):
|
|
41
|
+
for alias in node.names:
|
|
42
|
+
if alias.name.startswith("project_workflow."):
|
|
43
|
+
dependency = alias.name.split(".")[1]
|
|
44
|
+
if dependency in names:
|
|
45
|
+
dependencies.add(dependency)
|
|
46
|
+
return sorted(dependencies)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def top_level_definitions(path: Path) -> list[str]:
|
|
50
|
+
return sorted(
|
|
51
|
+
node.name
|
|
52
|
+
for node in ast.parse(path.read_text(encoding="utf-8")).body
|
|
53
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def adapter_common_imports(path: Path) -> list[str]:
|
|
58
|
+
imported = []
|
|
59
|
+
for node in ast.walk(ast.parse(path.read_text(encoding="utf-8"))):
|
|
60
|
+
if isinstance(node, ast.ImportFrom) and (node.module or "").endswith("adapter_common"):
|
|
61
|
+
imported.extend(alias.name for alias in node.names)
|
|
62
|
+
return sorted(set(imported))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def payload() -> dict[str, object]:
|
|
66
|
+
paths = runtime_paths()
|
|
67
|
+
names = {path.stem for path in paths}
|
|
68
|
+
order = {path.stem: index for index, path in enumerate(paths)}
|
|
69
|
+
modules = []
|
|
70
|
+
definition_owners: dict[str, list[str]] = {}
|
|
71
|
+
for path in paths:
|
|
72
|
+
definitions = top_level_definitions(path)
|
|
73
|
+
for name in definitions:
|
|
74
|
+
definition_owners.setdefault(name, []).append(path.stem)
|
|
75
|
+
dependencies = internal_dependencies(path, names)
|
|
76
|
+
modules.append(
|
|
77
|
+
{
|
|
78
|
+
"name": path.stem,
|
|
79
|
+
"path": path.relative_to(ROOT).as_posix(),
|
|
80
|
+
"line_count": len(path.read_text(encoding="utf-8").splitlines()),
|
|
81
|
+
"top_level_definition_count": len(definitions),
|
|
82
|
+
"dependencies": dependencies,
|
|
83
|
+
"dependencies_precede_module": all(
|
|
84
|
+
order[dependency] < order[path.stem] for dependency in dependencies
|
|
85
|
+
),
|
|
86
|
+
"sha256": sha256(path),
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
duplicates = {name: owners for name, owners in definition_owners.items() if len(owners) > 1}
|
|
90
|
+
package = ROOT / "src/project_workflow"
|
|
91
|
+
common = package / "adapter_common.py"
|
|
92
|
+
codex = package / "codex_adapter.py"
|
|
93
|
+
claude = package / "claude_adapter.py"
|
|
94
|
+
template = package / "templates/workflow.py"
|
|
95
|
+
helper = ROOT / ".project-workflow/cli/workflow.py"
|
|
96
|
+
adapter_records = []
|
|
97
|
+
for path in (common, codex, claude):
|
|
98
|
+
installed = ROOT / ".project-workflow/cli" / path.name
|
|
99
|
+
adapter_records.append(
|
|
100
|
+
{
|
|
101
|
+
"name": path.stem,
|
|
102
|
+
"line_count": len(path.read_text(encoding="utf-8").splitlines()),
|
|
103
|
+
"sha256": sha256(path),
|
|
104
|
+
"installed_sha256": sha256(installed),
|
|
105
|
+
"installed_matches_source": path.read_bytes() == installed.read_bytes(),
|
|
106
|
+
"common_imports": adapter_common_imports(path),
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
return {
|
|
110
|
+
"schema_version": 1,
|
|
111
|
+
"runtime_manifest": MANIFEST.relative_to(ROOT).as_posix(),
|
|
112
|
+
"runtime_module_count": len(modules),
|
|
113
|
+
"runtime_modules": modules,
|
|
114
|
+
"duplicate_top_level_definitions": duplicates,
|
|
115
|
+
"dependency_order_valid": all(record["dependencies_precede_module"] for record in modules),
|
|
116
|
+
"entry_module_under_2000_lines": modules[-1]["line_count"] < 2_000,
|
|
117
|
+
"domain_modules_under_5000_lines": all(
|
|
118
|
+
record["line_count"] < 5_000 for record in modules[:-1]
|
|
119
|
+
),
|
|
120
|
+
"generated_runtime": {
|
|
121
|
+
"template_sha256": sha256(template),
|
|
122
|
+
"installed_helper_sha256": sha256(helper),
|
|
123
|
+
"byte_identical": template.read_bytes() == helper.read_bytes(),
|
|
124
|
+
},
|
|
125
|
+
"adapters": adapter_records,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main() -> int:
|
|
130
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
131
|
+
parser.add_argument("--output", type=Path, required=True)
|
|
132
|
+
args = parser.parse_args()
|
|
133
|
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
134
|
+
args.output.write_text(
|
|
135
|
+
json.dumps(payload(), indent=2, sort_keys=True) + "\n",
|
|
136
|
+
encoding="utf-8",
|
|
137
|
+
)
|
|
138
|
+
print(args.output)
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if __name__ == "__main__":
|
|
143
|
+
raise SystemExit(main())
|