pactkit-opencode 2.8.0__tar.gz → 2.9.1__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.
Files changed (19) hide show
  1. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/PKG-INFO +2 -2
  2. pactkit_opencode-2.9.1/README.md +99 -0
  3. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/pyproject.toml +2 -2
  4. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode/deployer.py +9 -23
  5. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode.egg-info/PKG-INFO +2 -2
  6. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode.egg-info/SOURCES.txt +1 -0
  7. pactkit_opencode-2.9.1/src/pactkit_opencode.egg-info/requires.txt +1 -0
  8. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_story073_command_model_routing.py +7 -17
  9. pactkit_opencode-2.8.0/src/pactkit_opencode.egg-info/requires.txt +0 -1
  10. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/setup.cfg +0 -0
  11. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode/__init__.py +0 -0
  12. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode.egg-info/dependency_links.txt +0 -0
  13. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode.egg-info/entry_points.txt +0 -0
  14. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/src/pactkit_opencode.egg-info/top_level.txt +0 -0
  15. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_bug035_opencode_dual_layer.py +0 -0
  16. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_deploy_opencode_parity.py +0 -0
  17. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_story069_opencode_format.py +0 -0
  18. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_story070_opencode_compliance.py +0 -0
  19. {pactkit_opencode-2.8.0 → pactkit_opencode-2.9.1}/tests/test_story071_opencode_config_parity.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactkit-opencode
3
- Version: 2.8.0
3
+ Version: 2.9.1
4
4
  Summary: PactKit adapter for OpenCode IDE
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
7
- Requires-Dist: pactkit>=2.8.0
7
+ Requires-Dist: pactkit>=2.9.0
@@ -0,0 +1,99 @@
1
+ # pactkit-opencode
2
+
3
+ > PactKit PDCA workflow framework adapted for [OpenCode](https://opencode.ai).
4
+
5
+ [![PyPI version](https://badge.fury.io/py/pactkit-opencode.svg)](https://pypi.org/project/pactkit-opencode/)
6
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## What is this?
10
+
11
+ **pactkit-opencode** brings the [PactKit](https://pactkit.dev) spec-driven development workflow to OpenCode IDE. It deploys:
12
+
13
+ - **Commands** (`commands/*.md`) — 11 PDCA workflow commands, auto-discovered by OpenCode (invoked via `/project-plan`, `/project-act`, etc.)
14
+ - **Skills** (`skills/*/SKILL.md`) — 10 embedded skills loaded by AI agent on demand
15
+ - **Agents** (`agents/*.md`) — 9 specialized agent definitions
16
+ - **Rules** (`rules/*.md`) — Governance rules loaded per-command
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install pactkit
22
+ ```
23
+
24
+ > `pactkit-opencode` is automatically installed as a dependency of `pactkit`.
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ # Deploy PactKit to OpenCode (~/.config/opencode/)
30
+ pactkit init --format opencode
31
+
32
+ # Update when pactkit is upgraded
33
+ pactkit upgrade --format opencode
34
+ ```
35
+
36
+ Then in OpenCode, use commands like:
37
+
38
+ ```
39
+ /project-plan "Add user authentication"
40
+ /project-act STORY-001
41
+ /project-done
42
+ ```
43
+
44
+ ## What Gets Deployed
45
+
46
+ ```
47
+ ~/.config/opencode/
48
+ ├── AGENTS.md # Global constitution
49
+ ├── rules/ # Governance rule modules
50
+ ├── commands/ # 11 PDCA command playbooks (auto-discovered by OpenCode)
51
+ ├── agents/ # 9 agent definitions (mode: subagent)
52
+ ├── skills/ # 10 skill packages (AI agent loads on demand)
53
+ └── opencode.json # Global config (model routing, instructions)
54
+
55
+ ./ # Project root
56
+ ├── .opencode/
57
+ │ ├── pactkit.yaml # Project config
58
+ │ └── AGENTS.local.md # Your custom instructions (never overwritten)
59
+ ```
60
+
61
+ ## OpenCode Architecture
62
+
63
+ OpenCode has two separate mechanisms for extending the AI assistant:
64
+
65
+ | Mechanism | Location | Invocation | Purpose |
66
+ |-----------|----------|------------|---------|
67
+ | **Commands** | `commands/*.md` | User types `/command-name` | PDCA workflow entry points |
68
+ | **Skills** | `skills/*/SKILL.md` | AI agent loads via `skill()` | Embedded tools (visualize, board, scaffold) |
69
+
70
+ Commands are auto-discovered from `commands/*.md` — no `opencode.json` configuration needed.
71
+
72
+ ## Key Differences from Claude Code
73
+
74
+ | Feature | Claude Code | OpenCode |
75
+ |---------|-------------|----------|
76
+ | Commands | Skills-only (`skills/project-*/SKILL.md`) | Dual: `commands/` + `skills/` |
77
+ | Config dir | `~/.claude/` | `~/.config/opencode/` |
78
+ | Agent format | Native multi-agent | `mode: subagent` |
79
+ | Model routing | Via skill frontmatter | Via `opencode.json` command entries |
80
+ | Rule loading | `@import` directives | Inline embedding per command |
81
+
82
+ ## Development
83
+
84
+ ```bash
85
+ git clone https://github.com/pactkit/pactkit-opencode.git
86
+ cd pactkit-opencode
87
+ pip install -e .
88
+ pytest tests/ -v
89
+ ```
90
+
91
+ ## License
92
+
93
+ MIT License - see [LICENSE](LICENSE) for details.
94
+
95
+ ## Related Projects
96
+
97
+ - [PactKit](https://pactkit.dev) — Core framework
98
+ - [pactkit-codex](https://github.com/pactkit/pactkit-codex) — Adapter for OpenAI Codex CLI
99
+ - [OpenCode](https://opencode.ai) — AI-powered coding IDE
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pactkit-opencode"
7
- version = "2.8.0"
7
+ version = "2.9.1"
8
8
  description = "PactKit adapter for OpenCode IDE"
9
9
  requires-python = ">=3.10"
10
10
  license = "MIT"
11
11
  dependencies = [
12
- "pactkit>=2.8.0",
12
+ "pactkit>=2.9.0",
13
13
  ]
14
14
 
15
15
  [project.entry-points."pactkit.deployers"]
@@ -297,33 +297,19 @@ class OpenCodeDeployer(DeployerBase):
297
297
  config["instructions"] = existing
298
298
 
299
299
  # OpenCode auto-discovers commands from commands/*.md directory.
300
- # opencode.json "command" entries are only needed for model routing overrides.
301
- # NOTE: "template" in JSON is inline prompt text, NOT a file path — do not write it.
300
+ # opencode.json "command" section requires BOTH "model" AND "template" fields.
301
+ # Since we don't control template content (it's inline prompt text, not a file path),
302
+ # we must NOT write model-only entries — they cause OpenCode validation errors.
303
+ # Clean up any PactKit-managed command entries that lack template.
302
304
  cmd_config = config.get("command", {})
303
- if enabled_commands:
304
- # Remove stale command entries not in enabled set
305
- stale_keys = [k for k in cmd_config if k.startswith("project-") and k not in enabled_commands]
306
- for k in stale_keys:
307
- del cmd_config[k]
308
- # Remove legacy "template" fields (was incorrectly treated as file path)
309
- for cmd_name in list(cmd_config):
310
- if cmd_name.startswith("project-") and "template" in cmd_config[cmd_name]:
311
- del cmd_config[cmd_name]["template"]
312
- # Remove entry entirely if only template was present
313
- if not cmd_config[cmd_name]:
314
- del cmd_config[cmd_name]
315
-
316
- # Apply model routing
317
- if command_models and providers:
318
- for cmd_name, model_short in command_models.items():
319
- model_id = OpenCodeDeployer._resolve_opencode_model_id(model_short, providers)
320
- if model_id:
321
- if cmd_name not in cmd_config:
322
- cmd_config[cmd_name] = {}
323
- cmd_config[cmd_name]["model"] = model_id
305
+ for cmd_name in list(cmd_config):
306
+ if cmd_name.startswith("project-") and "template" not in cmd_config[cmd_name]:
307
+ del cmd_config[cmd_name]
324
308
 
325
309
  if cmd_config:
326
310
  config["command"] = cmd_config
311
+ else:
312
+ config.pop("command", None)
327
313
 
328
314
  content = json.dumps(config, indent=2, ensure_ascii=False) + "\n"
329
315
  atomic_write(json_path, content)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactkit-opencode
3
- Version: 2.8.0
3
+ Version: 2.9.1
4
4
  Summary: PactKit adapter for OpenCode IDE
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
7
- Requires-Dist: pactkit>=2.8.0
7
+ Requires-Dist: pactkit>=2.9.0
@@ -1,3 +1,4 @@
1
+ README.md
1
2
  pyproject.toml
2
3
  src/pactkit_opencode/__init__.py
3
4
  src/pactkit_opencode/deployer.py
@@ -40,26 +40,16 @@ class TestAC1CommandModel:
40
40
  deploy(format="opencode", target=str(out))
41
41
  return out
42
42
 
43
- def test_act_model_in_opencode_json(self, tmp_path):
44
- """project-act model routing is in opencode.json command section."""
43
+ def test_no_model_only_entries_in_opencode_json(self, tmp_path):
44
+ """Model-only command entries must NOT be written — OpenCode requires both model AND template."""
45
45
  out = self._deploy_with_providers(tmp_path)
46
46
  data = json.loads((out / "opencode.json").read_text())
47
47
  cmd_config = data.get("command", {})
48
- assert "project-act" in cmd_config
49
- assert "model" in cmd_config["project-act"]
50
- assert "sonnet" in cmd_config["project-act"]["model"]
51
-
52
- def test_done_model_in_opencode_json(self, tmp_path):
53
- """project-done model routing is in opencode.json command section."""
54
- out = self._deploy_with_providers(tmp_path)
55
- data = json.loads((out / "opencode.json").read_text())
56
- assert "project-done" in data.get("command", {})
57
-
58
- def test_check_model_in_opencode_json(self, tmp_path):
59
- """project-check model routing is in opencode.json command section."""
60
- out = self._deploy_with_providers(tmp_path)
61
- data = json.loads((out / "opencode.json").read_text())
62
- assert "project-check" in data.get("command", {})
48
+ for cmd_name, cmd_val in cmd_config.items():
49
+ if cmd_name.startswith("project-"):
50
+ assert "template" in cmd_val, (
51
+ f"command.{cmd_name} has model but no template — OpenCode validation will fail"
52
+ )
63
53
 
64
54
  def test_frontmatter_has_no_model(self, tmp_path):
65
55
  """Command frontmatter should NOT contain model: (routing is in opencode.json)."""
@@ -1 +0,0 @@
1
- pactkit>=2.8.0