cowork-flow 1.2.0 → 1.3.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +4 -3
  3. package/package.json +1 -1
  4. package/template/.claude/hooks/inject-workflow-state.py +12 -98
  5. package/template/.codex/hooks/inject-workflow-state.py +13 -89
  6. package/template/.cowork-flow/.version +1 -1
  7. package/template/.cowork-flow/scripts/adapters/cli/task.py +4 -1
  8. package/template/.cowork-flow/scripts/adapters/cli/task_context_commands.py +65 -0
  9. package/template/.cowork-flow/scripts/adapters/cli/task_parser.py +23 -0
  10. package/template/.cowork-flow/scripts/adapters/host/claude_code_policy.py +52 -0
  11. package/template/.cowork-flow/scripts/adapters/host/codex_policy.py +61 -0
  12. package/template/.cowork-flow/scripts/adapters/host/inject.py +249 -0
  13. package/template/.cowork-flow/scripts/adapters/host/workflow_state_hook.py +280 -35
  14. package/template/.cowork-flow/scripts/adapters/host/zcode_policy.py +230 -0
  15. package/template/.cowork-flow/scripts/adapters/mcp/state_server.py +2 -5
  16. package/template/.cowork-flow/scripts/runtime/session_state.py +19 -9
  17. package/template/.cowork-flow/scripts/services/context_discovery.py +18 -5
  18. package/template/.cowork-flow/scripts/services/fact_view.py +14 -0
  19. package/template/.cowork-flow/scripts/services/spec_check.py +34 -12
  20. package/template/.cowork-flow/scripts/services/task_context.py +0 -1
  21. package/template/.cowork-flow/spec/contracts/context-injection.md +24 -20
  22. package/template/.cowork-flow/spec/contracts/fact-layer-access.md +43 -8
  23. package/template/.cowork-flow/spec/contracts/spec-checks.md +40 -8
  24. package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +21 -0
  25. package/template/.cowork-flow/spec/runtime/contract-registry.json +12 -0
  26. package/template/.opencode/plugins/cowork-flow.js +12 -0
  27. package/template/.zcode/.zcode-plugin/plugin.json +1 -1
  28. package/template/.zcode/hooks/inject-context.js +95 -971
  29. package/template/skills/agent-dispatch/SKILL.md +15 -0
  30. package/template/skills/runtime-health/scripts/doctor.py +90 -0
  31. package/template/skills/task-planning/SKILL.md +1 -0
  32. package/template/skills/task-review/SKILL.md +1 -0
  33. package/template/.zcode/hooks/inject-context.selfcheck.mjs +0 -795
@@ -27,6 +27,21 @@ Use this Skill only inside fixed subagents such as `cowork-implement`,
27
27
  - Treat runtime gates as CLI adapters backed by kernel services; this Skill may
28
28
  explain when to run or report them, but does not enforce them.
29
29
 
30
+ ## Spec Self-Check
31
+
32
+ Delegated subagent tool calls receive no edit-phase hook feedback on hosts
33
+ whose plugin hooks cover only the main session stream — a `spec-check[...]
34
+ violation` line never reaches this session, even when the edit violates a
35
+ declared check. Before reporting completion after any file change, run:
36
+
37
+ ```text
38
+ ./.cowork-flow/run spec-check
39
+ ```
40
+
41
+ Fix every reported violation and re-run until the summary is clean, or report
42
+ the remaining violations as blockers. Honor any hook feedback the host does
43
+ deliver; the self-check exists because delivery is not guaranteed.
44
+
30
45
  ## Role Outputs
31
46
 
32
47
  - `cowork-implement`: report changed files, acceptance IDs, verification
@@ -641,6 +641,92 @@ def check_spec_checks(repo_root: Path) -> list[dict[str, str]]:
641
641
  return issues
642
642
 
643
643
 
644
+ def _global_mcp_registered() -> bool:
645
+ """Tolerant probe of user-level host configs for a cowork-flow MCP
646
+ entry. Read-only; missing files simply mean "not registered"."""
647
+ import os
648
+
649
+ home = Path(os.path.expanduser("~"))
650
+ candidates = (
651
+ home / ".zcode" / "cli" / "config.json",
652
+ home / ".claude.json",
653
+ home / ".codex" / "config.toml",
654
+ )
655
+ for path in candidates:
656
+ try:
657
+ if path.is_file() and "cowork-flow" in path.read_text(
658
+ encoding="utf-8", errors="replace"
659
+ ):
660
+ return True
661
+ except OSError:
662
+ continue
663
+ return False
664
+
665
+
666
+ def check_mcp_registration(repo_root: Path) -> list[dict[str, str]]:
667
+ """MCP fact-layer registration health. Advisory only (never fatal):
668
+ global registration is a supported default, so absence is a hint, not
669
+ an error. Reports project-level .mcp.json presence and the duplicate
670
+ global+project combination."""
671
+ issues: list[dict[str, str]] = []
672
+ project_registered = False
673
+ project_mcp = repo_root / ".mcp.json"
674
+ if project_mcp.is_file():
675
+ try:
676
+ data = json.loads(project_mcp.read_text(encoding="utf-8"))
677
+ servers = (
678
+ data.get("mcpServers") if isinstance(data, dict) else None
679
+ )
680
+ project_registered = isinstance(servers, dict) and any(
681
+ "cowork" in str(name).lower() for name in servers
682
+ )
683
+ issues.append(
684
+ {
685
+ "kind": "mcp",
686
+ "status": "project",
687
+ "message": (
688
+ "project .mcp.json registers the fact layer"
689
+ if project_registered
690
+ else "project .mcp.json present but no cowork-flow server entry"
691
+ ),
692
+ }
693
+ )
694
+ except (OSError, json.JSONDecodeError, ValueError):
695
+ issues.append(
696
+ {
697
+ "kind": "mcp",
698
+ "status": "project",
699
+ "message": "project .mcp.json is not valid JSON",
700
+ }
701
+ )
702
+ global_registered = _global_mcp_registered()
703
+ if project_registered and global_registered:
704
+ issues.append(
705
+ {
706
+ "kind": "mcp",
707
+ "status": "duplicate",
708
+ "message": (
709
+ "cowork-flow is registered both globally and at project "
710
+ "level; hosts deduplicate by server name, but removing "
711
+ "one keeps the tool list clean"
712
+ ),
713
+ }
714
+ )
715
+ if not project_registered and not global_registered:
716
+ issues.append(
717
+ {
718
+ "kind": "mcp",
719
+ "status": "absent",
720
+ "message": (
721
+ "fact layer not registered: register globally with "
722
+ "`cowork-flow mcp-state`, or add a project .mcp.json "
723
+ "(see spec/contracts/fact-layer-access.md)"
724
+ ),
725
+ }
726
+ )
727
+ return issues
728
+
729
+
644
730
  def _all_check_result(repo_root: Path) -> dict[str, object]:
645
731
  host_issues = _host_issues(repo_root)
646
732
  runtime_errors = check_runtime(repo_root)
@@ -649,6 +735,7 @@ def _all_check_result(repo_root: Path) -> dict[str, object]:
649
735
  state_recovery_issues = check_state_recovery(repo_root)
650
736
  session_hygiene_issues = check_session_hygiene(repo_root)
651
737
  spec_check_issues = check_spec_checks(repo_root)
738
+ mcp_issues = check_mcp_registration(repo_root)
652
739
  errors: list[dict[str, object]] = []
653
740
  for issue in host_issues:
654
741
  errors.append({"kind": "host_adapter", **issue})
@@ -670,6 +757,7 @@ def _all_check_result(repo_root: Path) -> dict[str, object]:
670
757
  "stateRecovery": state_recovery_issues,
671
758
  "sessionHygiene": session_hygiene_issues,
672
759
  "specChecks": spec_check_issues,
760
+ "mcpRegistration": mcp_issues,
673
761
  },
674
762
  }
675
763
 
@@ -683,6 +771,8 @@ def _run_checks(repo_root: Path, *, structured: bool = False) -> int:
683
771
  _print_task_hygiene_issues(result["issues"]["taskHygiene"])
684
772
  _print_state_recovery_issues(result["issues"]["stateRecovery"])
685
773
  _print_session_hygiene_issues(result["issues"]["sessionHygiene"])
774
+ for issue in result["issues"]["mcpRegistration"]:
775
+ print(f"MCP ({issue['status']}): {issue['message']}")
686
776
  if errors:
687
777
  for error in errors:
688
778
  print(f"ERROR: {error['message']}", file=sys.stderr)
@@ -128,6 +128,7 @@ Then list task briefs, followed by integrated verification and completion checks
128
128
 
129
129
  - For Tiny tasks, keep the brief short but still name exact file boundaries, completion conditions, and verification commands.
130
130
  - For behavior changes, include a failing test before implementation when behavior can be tested.
131
+ - For implementation tasks whose changed files are covered by spec `checks:` declarations, include the spec self-check in the task's Verification Command (for example `./.cowork-flow/run spec-check`): delegated subagents receive no edit-phase hook feedback on some hosts (zcode), so the explicit command is the reliable pull path for both self-check and acceptance.
131
132
  - Do not add shallow tests just to satisfy process. Avoid tests that only assert existence, mirror implementation details, count mock calls without behavior, or snapshot empty structure.
132
133
  - For complex problems, test depth first: business invariants, cross-layer contracts, state transitions, error boundaries, and real regression paths before narrow unit cases.
133
134
  - Map behavior-changing tests to stable `decision-anchor.md` acceptance IDs when useful; do not create `tdd.jsonl` or write TDD evidence records into `check.jsonl`.
@@ -41,6 +41,7 @@ Read only what is needed for the current task:
41
41
  - **Specs**: project specs are updated when behavior/contracts changed, or the review states why no spec update is needed.
42
42
  - **Code quality**: naming, layering, error handling, state boundaries, security-sensitive paths, and complexity are reviewed against applicable user specs.
43
43
  - **Lifecycle blockers**: state/scope blockers are fixed before acceptance; review does not invent hard blockers for natural-language specs.
44
+ - **Delegated acceptance**: when the implementation came from a delegated subagent, run `./.cowork-flow/run spec-check` before accepting its report — delegated sessions receive no edit-phase hook feedback on some hosts (zcode), so the report can be silently non-compliant; every violation is fixed or blocks acceptance.
44
45
  - **Advisory facts**: helper output is used to focus review, not to declare pass/fail or block completion.
45
46
  - **Anti-self-proof**: every claimed pass maps to source, diff, test output, or lifecycle output.
46
47
  - **Anti-rationalization**: every accepted gap has an explicit user decision or narrow technical reason.