plantod 0.1.0__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.
- plantod-0.1.0/LICENSE +21 -0
- plantod-0.1.0/PKG-INFO +188 -0
- plantod-0.1.0/README.md +153 -0
- plantod-0.1.0/pyproject.toml +51 -0
- plantod-0.1.0/setup.cfg +4 -0
- plantod-0.1.0/src/plantod/__init__.py +6 -0
- plantod-0.1.0/src/plantod/adapters/__init__.py +6 -0
- plantod-0.1.0/src/plantod/adapters/base.py +59 -0
- plantod-0.1.0/src/plantod/adapters/cliagent.py +210 -0
- plantod-0.1.0/src/plantod/adapters/mock.py +64 -0
- plantod-0.1.0/src/plantod/adapters/registry.py +20 -0
- plantod-0.1.0/src/plantod/artifacts.py +81 -0
- plantod-0.1.0/src/plantod/cli.py +241 -0
- plantod-0.1.0/src/plantod/config.py +111 -0
- plantod-0.1.0/src/plantod/executor.py +94 -0
- plantod-0.1.0/src/plantod/gitutil.py +71 -0
- plantod-0.1.0/src/plantod/interactive.py +80 -0
- plantod-0.1.0/src/plantod/locking.py +50 -0
- plantod-0.1.0/src/plantod/orchestrator.py +138 -0
- plantod-0.1.0/src/plantod/parsing.py +37 -0
- plantod-0.1.0/src/plantod/planner.py +88 -0
- plantod-0.1.0/src/plantod/repo.py +94 -0
- plantod-0.1.0/src/plantod/retry.py +32 -0
- plantod-0.1.0/src/plantod/reviewer.py +69 -0
- plantod-0.1.0/src/plantod/schemas.py +215 -0
- plantod-0.1.0/src/plantod/scope.py +62 -0
- plantod-0.1.0/src/plantod/state.py +169 -0
- plantod-0.1.0/src/plantod/testrunner.py +38 -0
- plantod-0.1.0/src/plantod/ui.py +54 -0
- plantod-0.1.0/src/plantod.egg-info/PKG-INFO +188 -0
- plantod-0.1.0/src/plantod.egg-info/SOURCES.txt +41 -0
- plantod-0.1.0/src/plantod.egg-info/dependency_links.txt +1 -0
- plantod-0.1.0/src/plantod.egg-info/entry_points.txt +2 -0
- plantod-0.1.0/src/plantod.egg-info/requires.txt +9 -0
- plantod-0.1.0/src/plantod.egg-info/top_level.txt +1 -0
- plantod-0.1.0/tests/test_artifacts.py +31 -0
- plantod-0.1.0/tests/test_cliagent.py +40 -0
- plantod-0.1.0/tests/test_config.py +54 -0
- plantod-0.1.0/tests/test_escalation.py +41 -0
- plantod-0.1.0/tests/test_hardening.py +61 -0
- plantod-0.1.0/tests/test_orchestrator_mock.py +51 -0
- plantod-0.1.0/tests/test_scope.py +42 -0
- plantod-0.1.0/tests/test_state_machine.py +41 -0
plantod-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PLANTOD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
plantod-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plantod
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Planning-first, repo-aware AI coding orchestrator CLI
|
|
5
|
+
Author-email: PLANTOD <admin@beinsoft.co.id>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/wandi1209/plantod
|
|
8
|
+
Project-URL: Repository, https://github.com/wandi1209/plantod
|
|
9
|
+
Project-URL: Issues, https://github.com/wandi1209/plantod/issues
|
|
10
|
+
Keywords: ai,cli,coding,orchestrator,planning,agent,llm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development
|
|
21
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: typer>=0.12
|
|
27
|
+
Requires-Dist: rich>=13.7
|
|
28
|
+
Requires-Dist: pydantic>=2.6
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
33
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# PLANTOD
|
|
37
|
+
|
|
38
|
+
**Plan, Task, Orchestrate, Deliver** — a planning-first, repo-aware AI coding orchestrator CLI.
|
|
39
|
+
|
|
40
|
+
PLANTOD turns a natural-language request ("add login feature") into a structured
|
|
41
|
+
workflow: **plan → tasks → scoped execution → test → handoff → escalation → final review**.
|
|
42
|
+
A strong model plans and reviews; a fast model executes small, scoped tasks. All
|
|
43
|
+
decisions and outputs are written to `.plantod/` in the repo so the work is auditable.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m venv .venv && source .venv/bin/activate
|
|
49
|
+
pip install -e ".[dev]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Providers
|
|
53
|
+
|
|
54
|
+
PLANTOD drives **agentic coding CLIs** as its backends — one per role. Install the
|
|
55
|
+
CLI(s) for the providers you pick; each handles its own auth/model config.
|
|
56
|
+
|
|
57
|
+
| Provider | Binary | Invocation |
|
|
58
|
+
|----------|--------|-----------|
|
|
59
|
+
| `claude-code` | `claude` | `claude -p "<prompt>"` |
|
|
60
|
+
| `codex` | `codex` | `codex exec "<prompt>"` |
|
|
61
|
+
| `opencode` | `opencode` | `opencode run "<prompt>"` |
|
|
62
|
+
|
|
63
|
+
### `plantod login`
|
|
64
|
+
|
|
65
|
+
Set the provider + model for each role (planner / executor / reviewer):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
plantod login # interactive wizard (all roles)
|
|
69
|
+
plantod login --role executor --provider codex --model o4 # non-interactive, one role
|
|
70
|
+
plantod login --role planner --provider claude-code # model optional -> provider default
|
|
71
|
+
plantod login ... --project # save to THIS repo instead of global
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Config precedence (low → high): **defaults < global (`~/.config/plantod/config.yaml`) < project (`.plantod/config.yaml`)**.
|
|
75
|
+
`login` writes the global scope by default so settings carry across repos (NFR-02);
|
|
76
|
+
`--project` overrides for one repo. `plantod init` inherits the global defaults.
|
|
77
|
+
|
|
78
|
+
## Prerequisites
|
|
79
|
+
|
|
80
|
+
- Install the CLI for each provider you configure (see table above); each tool
|
|
81
|
+
manages its own authentication.
|
|
82
|
+
- `.env` in the repo root is auto-loaded into the environment (see `.env.example`)
|
|
83
|
+
for any provider that reads env vars.
|
|
84
|
+
- A **git repo** is required for the scope guard — run `plantod init` inside one.
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
plantod login # pick provider + model per role (see Providers)
|
|
90
|
+
plantod init # detect repo, scaffold .plantod/ (inherits global)
|
|
91
|
+
plantod plan "add login feature" # plan + break into tasks + run the default flow
|
|
92
|
+
plantod plan "..." --yes --review # approve gated tasks, run final review
|
|
93
|
+
plantod tasks # list tasks + status
|
|
94
|
+
plantod next # next runnable task
|
|
95
|
+
plantod run T001 # run a single task
|
|
96
|
+
plantod review R001 # final review for a requirement
|
|
97
|
+
plantod status # board summary
|
|
98
|
+
plantod resume # where the last session left off
|
|
99
|
+
plantod # interactive chat-like session
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Why planning-first saves tokens (cost model)
|
|
103
|
+
|
|
104
|
+
PLANTOD's economics come from **routing**: a strong, expensive model only *plans*
|
|
105
|
+
and *reviews* (low token volume, high-value reasoning), while a cheap, fast model
|
|
106
|
+
does the *bulk editing* (high token volume, low-level work). Most tokens in a coding
|
|
107
|
+
task are spent reading context and writing edits — so you want those on the cheap model.
|
|
108
|
+
|
|
109
|
+
**Illustrative example** — one feature = 1 plan + 4 tasks + 1 review. Token splits
|
|
110
|
+
below are *assumptions to show the shape of the saving*, not measurements:
|
|
111
|
+
|
|
112
|
+
| Stage | Tokens | All-in-one (strong model) | PLANTOD (routed) |
|
|
113
|
+
|-------|-------:|--------------------------:|-----------------:|
|
|
114
|
+
| Plan + review | ~30K | strong | strong |
|
|
115
|
+
| Task execution (×4) | ~200K | strong | **cheap executor** |
|
|
116
|
+
| **Total billed as** | ~230K | 230K × strong-rate | 30K × strong-rate + 200K × cheap-rate |
|
|
117
|
+
|
|
118
|
+
If the executor model is ~15× cheaper per token than the planner (a typical
|
|
119
|
+
fast-model vs frontier-model gap), the routed run costs roughly:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
strong_share = 30K
|
|
123
|
+
cheap_share = 200K / 15 ≈ 13.3K strong-equivalent tokens
|
|
124
|
+
routed_total ≈ 43.3K vs 230K → ~5× cheaper for this mix
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The exact multiple depends on your models and the plan/execution token ratio —
|
|
128
|
+
plug in current per-token prices for your planner and executor to get real numbers.
|
|
129
|
+
|
|
130
|
+
> **Honest caveat:** these figures are an illustrative model, not a benchmark.
|
|
131
|
+
> PLANTOD does not yet meter real token usage — **cost tracking is on the v2
|
|
132
|
+
> roadmap** (PRD §27). The structural saving (route bulk edits to a cheap model,
|
|
133
|
+
> keep reasoning on a strong one) holds regardless; the exact ratio is yours to measure.
|
|
134
|
+
|
|
135
|
+
Beyond cost, the planning-first flow also reduces *wasted* tokens: scoped tasks and
|
|
136
|
+
the scope guard stop the executor from sprawling across the repo and re-generating
|
|
137
|
+
work, which is where "just let the big model code" runs burn tokens on churn.
|
|
138
|
+
|
|
139
|
+
## How it works
|
|
140
|
+
|
|
141
|
+
- **Adapters** (`plantod/adapters/`) make backends swappable: `claude`, `opencode`, `mock`.
|
|
142
|
+
- **State machine** (`plantod/schemas.py`) enforces legal task transitions
|
|
143
|
+
(`pending → ready → in_progress → testing → done → reviewed`, plus `blocked → needs_planner_review`).
|
|
144
|
+
- **Approval gate** (`plantod/orchestrator.py`) auto-runs only low-risk, small-scope,
|
|
145
|
+
testable tasks; everything else asks for approval.
|
|
146
|
+
- **Artifacts** (`.plantod/`): `requirements/ plans/ tasks/ handoffs/ reviews/ logs/`,
|
|
147
|
+
markdown + YAML frontmatter; `board.json` / `session.json` for state.
|
|
148
|
+
|
|
149
|
+
## Configuration (`.plantod/config.yaml`)
|
|
150
|
+
|
|
151
|
+
| Key | Default | Meaning |
|
|
152
|
+
|-----|---------|---------|
|
|
153
|
+
| `planner` / `executor` / `reviewer` | `{provider, model}` per role | backend for each role — set via `plantod login` |
|
|
154
|
+
| default providers | claude-code / opencode / claude-code | planner / executor / reviewer |
|
|
155
|
+
| `auto_run_small_tasks` | true | auto-run low-risk tasks |
|
|
156
|
+
| `require_approval_for_architecture` | true | gate high-risk changes |
|
|
157
|
+
| `test_before_done` | true | run tests before marking done |
|
|
158
|
+
| `enforce_scope` | true | revert executor edits outside `files_allowed` |
|
|
159
|
+
| `apply_requires_approval` | false | confirm the in-scope diff before keeping it |
|
|
160
|
+
| `exec_timeout_s` / `test_timeout_s` | 900 / 600 | subprocess timeouts |
|
|
161
|
+
| `max_retries` | 3 | retry transient backend failures / cap replans |
|
|
162
|
+
| `auto_replan_on_escalation` | true | planner advises + retries an escalated task |
|
|
163
|
+
|
|
164
|
+
## Production notes
|
|
165
|
+
|
|
166
|
+
- **Scope guard** — after each executor run, any file changed outside the task's
|
|
167
|
+
`files_allowed` (or matching `files_forbidden`) is reverted via git and the task
|
|
168
|
+
is escalated. This is enforced, not just prompted.
|
|
169
|
+
- **State safety** — `board.json` / `session.json` and all artifacts are written
|
|
170
|
+
atomically (temp file + rename). A per-project advisory lock (`.plantod/.lock`)
|
|
171
|
+
stops concurrent runs from corrupting state.
|
|
172
|
+
- **Escalation loop** — a blocked task goes `needs_planner_review`; the planner
|
|
173
|
+
produces guidance and the task retries with narrower scope, capped by `max_retries`.
|
|
174
|
+
- **Resilience** — backend calls retry with exponential backoff; subprocesses have
|
|
175
|
+
timeouts; malformed model JSON is parsed defensively.
|
|
176
|
+
- Requires a **git repo** for the scope guard; run `plantod init` inside one.
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
pytest # state machine, artifacts, config, full mock-adapter flow
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Layout: `src/` package layout, entry point `plantod.cli:app`.
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|
plantod-0.1.0/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# PLANTOD
|
|
2
|
+
|
|
3
|
+
**Plan, Task, Orchestrate, Deliver** — a planning-first, repo-aware AI coding orchestrator CLI.
|
|
4
|
+
|
|
5
|
+
PLANTOD turns a natural-language request ("add login feature") into a structured
|
|
6
|
+
workflow: **plan → tasks → scoped execution → test → handoff → escalation → final review**.
|
|
7
|
+
A strong model plans and reviews; a fast model executes small, scoped tasks. All
|
|
8
|
+
decisions and outputs are written to `.plantod/` in the repo so the work is auditable.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
python -m venv .venv && source .venv/bin/activate
|
|
14
|
+
pip install -e ".[dev]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Providers
|
|
18
|
+
|
|
19
|
+
PLANTOD drives **agentic coding CLIs** as its backends — one per role. Install the
|
|
20
|
+
CLI(s) for the providers you pick; each handles its own auth/model config.
|
|
21
|
+
|
|
22
|
+
| Provider | Binary | Invocation |
|
|
23
|
+
|----------|--------|-----------|
|
|
24
|
+
| `claude-code` | `claude` | `claude -p "<prompt>"` |
|
|
25
|
+
| `codex` | `codex` | `codex exec "<prompt>"` |
|
|
26
|
+
| `opencode` | `opencode` | `opencode run "<prompt>"` |
|
|
27
|
+
|
|
28
|
+
### `plantod login`
|
|
29
|
+
|
|
30
|
+
Set the provider + model for each role (planner / executor / reviewer):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
plantod login # interactive wizard (all roles)
|
|
34
|
+
plantod login --role executor --provider codex --model o4 # non-interactive, one role
|
|
35
|
+
plantod login --role planner --provider claude-code # model optional -> provider default
|
|
36
|
+
plantod login ... --project # save to THIS repo instead of global
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Config precedence (low → high): **defaults < global (`~/.config/plantod/config.yaml`) < project (`.plantod/config.yaml`)**.
|
|
40
|
+
`login` writes the global scope by default so settings carry across repos (NFR-02);
|
|
41
|
+
`--project` overrides for one repo. `plantod init` inherits the global defaults.
|
|
42
|
+
|
|
43
|
+
## Prerequisites
|
|
44
|
+
|
|
45
|
+
- Install the CLI for each provider you configure (see table above); each tool
|
|
46
|
+
manages its own authentication.
|
|
47
|
+
- `.env` in the repo root is auto-loaded into the environment (see `.env.example`)
|
|
48
|
+
for any provider that reads env vars.
|
|
49
|
+
- A **git repo** is required for the scope guard — run `plantod init` inside one.
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
plantod login # pick provider + model per role (see Providers)
|
|
55
|
+
plantod init # detect repo, scaffold .plantod/ (inherits global)
|
|
56
|
+
plantod plan "add login feature" # plan + break into tasks + run the default flow
|
|
57
|
+
plantod plan "..." --yes --review # approve gated tasks, run final review
|
|
58
|
+
plantod tasks # list tasks + status
|
|
59
|
+
plantod next # next runnable task
|
|
60
|
+
plantod run T001 # run a single task
|
|
61
|
+
plantod review R001 # final review for a requirement
|
|
62
|
+
plantod status # board summary
|
|
63
|
+
plantod resume # where the last session left off
|
|
64
|
+
plantod # interactive chat-like session
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Why planning-first saves tokens (cost model)
|
|
68
|
+
|
|
69
|
+
PLANTOD's economics come from **routing**: a strong, expensive model only *plans*
|
|
70
|
+
and *reviews* (low token volume, high-value reasoning), while a cheap, fast model
|
|
71
|
+
does the *bulk editing* (high token volume, low-level work). Most tokens in a coding
|
|
72
|
+
task are spent reading context and writing edits — so you want those on the cheap model.
|
|
73
|
+
|
|
74
|
+
**Illustrative example** — one feature = 1 plan + 4 tasks + 1 review. Token splits
|
|
75
|
+
below are *assumptions to show the shape of the saving*, not measurements:
|
|
76
|
+
|
|
77
|
+
| Stage | Tokens | All-in-one (strong model) | PLANTOD (routed) |
|
|
78
|
+
|-------|-------:|--------------------------:|-----------------:|
|
|
79
|
+
| Plan + review | ~30K | strong | strong |
|
|
80
|
+
| Task execution (×4) | ~200K | strong | **cheap executor** |
|
|
81
|
+
| **Total billed as** | ~230K | 230K × strong-rate | 30K × strong-rate + 200K × cheap-rate |
|
|
82
|
+
|
|
83
|
+
If the executor model is ~15× cheaper per token than the planner (a typical
|
|
84
|
+
fast-model vs frontier-model gap), the routed run costs roughly:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
strong_share = 30K
|
|
88
|
+
cheap_share = 200K / 15 ≈ 13.3K strong-equivalent tokens
|
|
89
|
+
routed_total ≈ 43.3K vs 230K → ~5× cheaper for this mix
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The exact multiple depends on your models and the plan/execution token ratio —
|
|
93
|
+
plug in current per-token prices for your planner and executor to get real numbers.
|
|
94
|
+
|
|
95
|
+
> **Honest caveat:** these figures are an illustrative model, not a benchmark.
|
|
96
|
+
> PLANTOD does not yet meter real token usage — **cost tracking is on the v2
|
|
97
|
+
> roadmap** (PRD §27). The structural saving (route bulk edits to a cheap model,
|
|
98
|
+
> keep reasoning on a strong one) holds regardless; the exact ratio is yours to measure.
|
|
99
|
+
|
|
100
|
+
Beyond cost, the planning-first flow also reduces *wasted* tokens: scoped tasks and
|
|
101
|
+
the scope guard stop the executor from sprawling across the repo and re-generating
|
|
102
|
+
work, which is where "just let the big model code" runs burn tokens on churn.
|
|
103
|
+
|
|
104
|
+
## How it works
|
|
105
|
+
|
|
106
|
+
- **Adapters** (`plantod/adapters/`) make backends swappable: `claude`, `opencode`, `mock`.
|
|
107
|
+
- **State machine** (`plantod/schemas.py`) enforces legal task transitions
|
|
108
|
+
(`pending → ready → in_progress → testing → done → reviewed`, plus `blocked → needs_planner_review`).
|
|
109
|
+
- **Approval gate** (`plantod/orchestrator.py`) auto-runs only low-risk, small-scope,
|
|
110
|
+
testable tasks; everything else asks for approval.
|
|
111
|
+
- **Artifacts** (`.plantod/`): `requirements/ plans/ tasks/ handoffs/ reviews/ logs/`,
|
|
112
|
+
markdown + YAML frontmatter; `board.json` / `session.json` for state.
|
|
113
|
+
|
|
114
|
+
## Configuration (`.plantod/config.yaml`)
|
|
115
|
+
|
|
116
|
+
| Key | Default | Meaning |
|
|
117
|
+
|-----|---------|---------|
|
|
118
|
+
| `planner` / `executor` / `reviewer` | `{provider, model}` per role | backend for each role — set via `plantod login` |
|
|
119
|
+
| default providers | claude-code / opencode / claude-code | planner / executor / reviewer |
|
|
120
|
+
| `auto_run_small_tasks` | true | auto-run low-risk tasks |
|
|
121
|
+
| `require_approval_for_architecture` | true | gate high-risk changes |
|
|
122
|
+
| `test_before_done` | true | run tests before marking done |
|
|
123
|
+
| `enforce_scope` | true | revert executor edits outside `files_allowed` |
|
|
124
|
+
| `apply_requires_approval` | false | confirm the in-scope diff before keeping it |
|
|
125
|
+
| `exec_timeout_s` / `test_timeout_s` | 900 / 600 | subprocess timeouts |
|
|
126
|
+
| `max_retries` | 3 | retry transient backend failures / cap replans |
|
|
127
|
+
| `auto_replan_on_escalation` | true | planner advises + retries an escalated task |
|
|
128
|
+
|
|
129
|
+
## Production notes
|
|
130
|
+
|
|
131
|
+
- **Scope guard** — after each executor run, any file changed outside the task's
|
|
132
|
+
`files_allowed` (or matching `files_forbidden`) is reverted via git and the task
|
|
133
|
+
is escalated. This is enforced, not just prompted.
|
|
134
|
+
- **State safety** — `board.json` / `session.json` and all artifacts are written
|
|
135
|
+
atomically (temp file + rename). A per-project advisory lock (`.plantod/.lock`)
|
|
136
|
+
stops concurrent runs from corrupting state.
|
|
137
|
+
- **Escalation loop** — a blocked task goes `needs_planner_review`; the planner
|
|
138
|
+
produces guidance and the task retries with narrower scope, capped by `max_retries`.
|
|
139
|
+
- **Resilience** — backend calls retry with exponential backoff; subprocesses have
|
|
140
|
+
timeouts; malformed model JSON is parsed defensively.
|
|
141
|
+
- Requires a **git repo** for the scope guard; run `plantod init` inside one.
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pytest # state machine, artifacts, config, full mock-adapter flow
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Layout: `src/` package layout, entry point `plantod.cli:app`.
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "plantod"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Planning-first, repo-aware AI coding orchestrator CLI"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "PLANTOD", email = "admin@beinsoft.co.id" }]
|
|
13
|
+
keywords = ["ai", "cli", "coding", "orchestrator", "planning", "agent", "llm"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development",
|
|
25
|
+
"Topic :: Software Development :: Code Generators",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"typer>=0.12",
|
|
30
|
+
"rich>=13.7",
|
|
31
|
+
"pydantic>=2.6",
|
|
32
|
+
"pyyaml>=6.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = ["pytest>=8.0", "build>=1.2", "twine>=5.0"]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/wandi1209/plantod"
|
|
40
|
+
Repository = "https://github.com/wandi1209/plantod"
|
|
41
|
+
Issues = "https://github.com/wandi1209/plantod/issues"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
plantod = "plantod.cli:app"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
where = ["src"]
|
|
48
|
+
include = ["plantod*"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
plantod-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""ModelAdapter interface + result types (PRD 14.1, NFR-03)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
|
|
8
|
+
from ..repo import RepoContext
|
|
9
|
+
from ..schemas import Handoff, Task
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PlanResult:
|
|
14
|
+
title: str
|
|
15
|
+
summary: str
|
|
16
|
+
risk_level: str
|
|
17
|
+
# each task dict is validated into a Task by the planner layer
|
|
18
|
+
tasks: list[dict] = field(default_factory=list)
|
|
19
|
+
raw: str = ""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class ExecResult:
|
|
24
|
+
files_changed: list[str] = field(default_factory=list)
|
|
25
|
+
summary: str = ""
|
|
26
|
+
diff: str = ""
|
|
27
|
+
escalate: bool = False
|
|
28
|
+
escalate_reason: str = ""
|
|
29
|
+
raw: str = ""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class ReviewResult:
|
|
34
|
+
verdict: str = "approve" # approve | revise
|
|
35
|
+
summary: str = ""
|
|
36
|
+
findings: list[str] = field(default_factory=list)
|
|
37
|
+
raw: str = ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ModelAdapter(ABC):
|
|
41
|
+
"""Backend-agnostic model interface. Concrete adapters wrap a provider."""
|
|
42
|
+
|
|
43
|
+
name: str = "adapter"
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def plan(self, request: str, repo: RepoContext) -> PlanResult: ...
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def execute(self, task: Task, repo: RepoContext) -> ExecResult: ...
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def review(self, request: str, handoffs: list[Handoff], repo: RepoContext) -> ReviewResult: ...
|
|
53
|
+
|
|
54
|
+
def advise(self, task: Task, reason: str, repo: RepoContext) -> str:
|
|
55
|
+
"""Planner guidance for a blocked/escalated task. Override in planner adapters."""
|
|
56
|
+
return (
|
|
57
|
+
f"Reduce scope and retry {task.id}. Split any architecture decision into a "
|
|
58
|
+
f"separate task. Blocking reason: {reason}"
|
|
59
|
+
)
|