obsidian-lean-coder 0.0.0-stage → 0.1.1
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.
- package/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +153 -2
- package/agents/olc-build.md +47 -0
- package/agents/olc-plan.md +44 -0
- package/dist/approval/index.d.ts +53 -0
- package/dist/approval/index.js +123 -0
- package/dist/build/index.d.ts +52 -0
- package/dist/build/index.js +146 -0
- package/dist/config/index.d.ts +56 -0
- package/dist/config/index.js +136 -0
- package/dist/core/project-identity.d.ts +53 -0
- package/dist/core/project-identity.js +141 -0
- package/dist/git/checkpoint.d.ts +63 -0
- package/dist/git/checkpoint.js +123 -0
- package/dist/git/inspection.d.ts +35 -0
- package/dist/git/inspection.js +78 -0
- package/dist/git/policy.d.ts +65 -0
- package/dist/git/policy.js +88 -0
- package/dist/git/restore.d.ts +63 -0
- package/dist/git/restore.js +143 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/init/index.d.ts +45 -0
- package/dist/init/index.js +178 -0
- package/dist/log/index.d.ts +68 -0
- package/dist/log/index.js +224 -0
- package/dist/memory/index.d.ts +89 -0
- package/dist/memory/index.js +166 -0
- package/dist/planning/index.d.ts +57 -0
- package/dist/planning/index.js +180 -0
- package/dist/plugin.d.ts +16 -0
- package/dist/plugin.js +46 -0
- package/dist/resume/index.d.ts +60 -0
- package/dist/resume/index.js +121 -0
- package/dist/session/index.d.ts +54 -0
- package/dist/session/index.js +108 -0
- package/dist/tasks/index.d.ts +59 -0
- package/dist/tasks/index.js +182 -0
- package/dist/taste/index.d.ts +79 -0
- package/dist/taste/index.js +162 -0
- package/dist/validation/index.d.ts +58 -0
- package/dist/validation/index.js +72 -0
- package/dist/vault/index.d.ts +50 -0
- package/dist/vault/index.js +153 -0
- package/dist/verify/index.d.ts +78 -0
- package/dist/verify/index.js +137 -0
- package/package.json +36 -4
- package/skills/olc-explore/SKILL.md +35 -0
- package/templates/.gitkeep +0 -0
- package/templates/activity-log.md +10 -0
- package/templates/checkpoint.md +24 -0
- package/templates/decision.md +19 -0
- package/templates/explore-report.md +23 -0
- package/templates/intent.md +23 -0
- package/templates/plan.md +27 -0
- package/templates/session-summary.md +26 -0
- package/templates/taste-rule.md +14 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to OLC (Obsidian Lean Coder) are recorded here.
|
|
4
|
+
OLC is pre-release: versions are `0.x` until a controlled-testing release says otherwise.
|
|
5
|
+
`package.json` shipped `"private": true` through 0.1.0; the flag was removed at publish time with explicit user approval, and 0.1.0 is live as [`obsidian-lean-coder`](https://www.npmjs.com/package/obsidian-lean-coder). Publishing a new version is still a separate explicitly approved action, never automatic.
|
|
6
|
+
|
|
7
|
+
## [0.1.1] — 2026-10-13 — plugin entrypoint fix
|
|
8
|
+
|
|
9
|
+
Fixes npm-package activation (reported: `npm install` worked but nothing appeared in OpenCode).
|
|
10
|
+
The package-root entrypoint `dist/index.js` exported only `OLC_VERSION`, so npm loaders —
|
|
11
|
+
which resolve the package root — never saw the plugin default export and ignored the package.
|
|
12
|
+
`src/index.ts` now re-exports the plugin default alongside `OLC_VERSION`.
|
|
13
|
+
Agents/skills still appear only via the project-local `.opencode` copy (by design, OLC-012).
|
|
14
|
+
|
|
15
|
+
- **Verification:** typecheck clean, build OK, mock-ctx plugin load (`id=olc`, correct payload),
|
|
16
|
+
full suite 140/140 pass, real-loader test (`loading plugin`, zero `failed to load plugin`).
|
|
17
|
+
- **Upgrade:** `npm install obsidian-lean-coder@0.1.1`, then list the package in `opencode.json`
|
|
18
|
+
`plugins` (see README §2).
|
|
19
|
+
|
|
20
|
+
## [0.1.0] — 2026-10-13 — MVP pre-release
|
|
21
|
+
|
|
22
|
+
First usable version for controlled testing. One full user journey is covered by an automated end-to-end test (`tests/e2e.test.ts`, OLC-072).
|
|
23
|
+
|
|
24
|
+
**What works**
|
|
25
|
+
- Safe, idempotent project init (`initProject`): create-only, `preserved` reporting, `needs-decision` flow, `dryRun` preview.
|
|
26
|
+
- Planning workflow: draft/approve/revise/reject `intent.md` + `plan.md`, approval gate (`assertBuildReady`), scope-change return path.
|
|
27
|
+
- Bounded build frame: `beginTask` (identity + approval gate), `recordDecision`, `completeTask` (out-of-scope changes throw `SCOPE_CHANGED`, nothing completed silently).
|
|
28
|
+
- Evidence-backed verification: real command outcomes, bounded retries, escalation list; completion only on full pass.
|
|
29
|
+
- Safe Git checkpoints (`createCheckpoint`) and history-preserving restore (`restoreCheckpoint`): explicit owned paths only, pathspec commits, race guards; `git add .`/`-A`, plain `git commit`, `reset --hard`, and force-push are banned in OLC flows.
|
|
30
|
+
- Continuity: activity log (secret-scrubbed, append-only), resume context (read-only, confirmation-gated), plain-language Indonesian session summaries with event-mapped claims, progressive memory retrieval with project isolation, user-approved taste rules (`pending`→`active`/`rejected`, never silent).
|
|
31
|
+
- Session validation: `startSession` + `assertContextCurrent` revalidation wired into checkpoint/restore (vault unmounted, registry rewritten, or branch switched between operations blocks with zero writes).
|
|
32
|
+
- Packaging: `npm pack` ships `dist/` (17 modules), `agents/olc-plan.md` + `olc-build.md`, `skills/olc-explore/SKILL.md`, 8 `templates/*.md` (56 files, verified OLC-071). No dev-only dependency at runtime (`typescript` excluded).
|
|
33
|
+
- Docs: `README.md` distinguishes dev install vs plugin activation vs project init, with verified commands, troubleshooting, and security notes.
|
|
34
|
+
|
|
35
|
+
**Known limitations (not fixed in this release)**
|
|
36
|
+
- npm package name/scope unreserved (DECISIONS.md #1); minimum OpenCode version unpinned — smoke-tested against 2.0.27 only (#3).
|
|
37
|
+
- `dist/index.js` exports only `OLC_VERSION`; npm loaders resolve `dist/index.js`, so npm-package activation cannot work until the entrypoint is wired AND a name is reserved. Verified load path is local-file `.opencode/plugins/<name>/index.js` (README §2).
|
|
38
|
+
- `opencode.json` `plugins`/`plugin` pointing at a package directory produced zero load attempts in this build.
|
|
39
|
+
- `/api/agent` + `/api/skill` returned `[]` for project-local files in this build (OLC-012 evidence did not reproduce); README verifies resource placement by file presence.
|
|
40
|
+
- Tool invocation end-to-end through a live model call not exercised (account billing); OLC-072 journey runs fully offline.
|
|
41
|
+
- Raw `approval`/`planning`/`tasks` vault helpers are ungated by design for MVP — all agent-facing write paths go through validated entry points.
|
|
42
|
+
- Pre-existing unrelated change in the working tree (`D .opencode/goals/...` claim file) is not part of this release and was left untouched.
|
|
43
|
+
|
|
44
|
+
## [0.0.1] — 2026-10-12 — development baseline
|
|
45
|
+
|
|
46
|
+
Internal scaffolding milestone: repo skeleton, TypeScript ESM build, plugin entrypoint (`olc_status`), config/identity/vault foundations. Not released.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mdhb2
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OLC — Obsidian Lean Coder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
OpenCode extension for project-scoped planning, memory, and safe Git checkpoints. On npm as `obsidian-lean-coder` (v0.1.1 fixes plugin activation — see CHANGELOG).
|
|
4
|
+
|
|
5
|
+
## Three separate steps
|
|
6
|
+
|
|
7
|
+
Do not confuse these. They are different operations with different commands:
|
|
8
|
+
|
|
9
|
+
| # | Step | What it does | Command |
|
|
10
|
+
|---|------|--------------|---------|
|
|
11
|
+
| 1 | **Dev install** | Install npm deps to hack on OLC itself | `npm ci && npm run build` |
|
|
12
|
+
| 2 | **Plugin activation** | Load OLC as an OpenCode plugin | `npm i obsidian-lean-coder` + `opencode.json` snippet below |
|
|
13
|
+
| 3 | **Project init** | Register one app repo + vault with OLC (`initProject`, idempotent, create-only) | via the `olc-init` skill in OpenCode (the tested path) |
|
|
14
|
+
|
|
15
|
+
## 1. Dev install
|
|
16
|
+
|
|
17
|
+
Requirements: Node >= 18.18, npm, git.
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
git clone <this-repo> olc && cd olc
|
|
21
|
+
npm ci
|
|
22
|
+
npm run build # tsc -p tsconfig.json → dist/
|
|
23
|
+
npm test # tsc -p tsconfig.tests.json && node --test "dist-tests/tests/**/*.test.js"
|
|
24
|
+
npm run typecheck
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Expected: build clean, typecheck clean. `npm test` runs the full suite (currently 140 tests). `npm pack --dry-run` shows what would ship (`dist/`, `agents/`, `skills/`, `templates/`).
|
|
28
|
+
|
|
29
|
+
> Published on npm as `obsidian-lean-coder` (MIT). Republishing needs a separate explicit approval — never publish by accident.
|
|
30
|
+
|
|
31
|
+
## 2. Plugin activation
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install obsidian-lean-coder
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then list it in your project's `opencode.json` (npm loaders resolve the package root `dist/index.js`, which since v0.1.1 carries the plugin default export alongside `OLC_VERSION`):
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"plugins": ["obsidian-lean-coder"]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Verify it loads (from the consuming project directory; the model call itself will fail without account funds, but plugin loading happens first):
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
OPENCODE_LOG_LEVEL=DEBUG opencode run --standalone "hi" --print-logs 2>&1 | grep -E "loading plugin.*obsidian-lean-coder|failed to load plugin"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Expected: a `loading plugin ... obsidian-lean-coder` line and **zero** `failed to load plugin` lines. (Verified 2026-10-13 via the equivalent local-file shape against the real loader; npm-registry install itself verified in OLC-071.)
|
|
52
|
+
|
|
53
|
+
> `npm install` alone shows nothing in OpenCode — that is normal. The package must be listed under `plugins`, and agents/skills never auto-appear: they are project-local files you copy yourself (next step). No restart or rebuild needed after editing `opencode.json`.
|
|
54
|
+
|
|
55
|
+
### Local dev path (this checkout, no npm)
|
|
56
|
+
|
|
57
|
+
An `index.js` under `.opencode/plugins/<name>/` auto-loads with no install step (proven in OLC-011, re-verified in OLC-071). The plugin entrypoint is `dist/plugin.js` (`src/plugin.ts` → `Plugin.define({ id: "olc" })`, one read-only `olc_status` tool, zero writes on load).
|
|
58
|
+
|
|
59
|
+
In your consuming project (replace `/home/you/olc` with your OLC checkout):
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
PKG=/home/you/olc # your OLC checkout — build it first (step 1)
|
|
63
|
+
mkdir -p .opencode/plugins/olc
|
|
64
|
+
printf '%s\n' 'export { default } from "file://'"$PKG"'/dist/plugin.js";' > .opencode/plugins/olc/index.js
|
|
65
|
+
printf '%s\n' '{ "type": "module", "dependencies": { "@opencode/plugin": "2.0.27" } }' > .opencode/plugins/olc/package.json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Verify with the same `grep` as above, expecting `.opencode/plugins/olc/index.js` in the loading line.
|
|
69
|
+
|
|
70
|
+
Then place the agent/skill resources project-locally (DECISIONS.md #2 — programmatic registration was rejected for MVP):
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
PKG=/home/you/olc # your OLC checkout
|
|
74
|
+
mkdir -p .opencode/agents .opencode/skills/olc-explore
|
|
75
|
+
cp "$PKG"/agents/olc-plan.md "$PKG"/agents/olc-build.md .opencode/agents/
|
|
76
|
+
cp "$PKG"/skills/olc-explore/SKILL.md .opencode/skills/olc-explore/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Discovery note: `/api/agent` and `/api/skill` returned `[]` for project-local files in this build — even for a minimal probe agent — so API listing is not a valid verification (OLC-012 evidence did not reproduce; TUI-side discovery untested). Verify by file presence instead:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
ls .opencode/agents/olc-plan.md .opencode/agents/olc-build.md .opencode/skills/olc-explore/SKILL.md
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`olc-plan`/`olc-build` agents and the `olc-explore` skill are picked up by OpenCode from these paths. Re-running the `cp` commands is safe as long as you have not customized the destination files — `cp` overwrites; the no-clobber guarantee belongs to `olc-init`, which reports existing files as `preserved` instead of overwriting them.
|
|
86
|
+
|
|
87
|
+
Supported versions: OpenCode 2.x with the V2 plugin API. OLC pins `@opencode/plugin` 2.0.27 to match the CLI it was smoke-tested against (see OLC-011). Other 2.x versions will likely work; 1.x will not. The exact minimum version is still open (DECISIONS.md #3).
|
|
88
|
+
|
|
89
|
+
## 3. Project init
|
|
90
|
+
|
|
91
|
+
`initProject` (`src/init/index.ts`) registers one app repo + vault. It is idempotent and **create-only**: existing files are reported `preserved`, never overwritten. Anything needing a human choice comes back as `status: "needs-decision"` — no prompting inside the module.
|
|
92
|
+
|
|
93
|
+
Run it via the `olc-init` skill inside OpenCode (recommended — the only tested path for MVP). A programmatic import is not yet wired: the package entrypoint (`dist/index.js`) exports `OLC_VERSION` plus the plugin default, and `initProject` lives in `src/init/index.ts` for internal/agent use.
|
|
94
|
+
|
|
95
|
+
What it creates (only when missing):
|
|
96
|
+
|
|
97
|
+
- `<repo>/.olc/config.json` — `{ schemaVersion, projectId, vaultPath }`. No secrets (keys matching `secret|token|password|api-key` are rejected).
|
|
98
|
+
- `<repo>/.olc/AGENTS.md` — stub instructions for agents. Review and customize.
|
|
99
|
+
- `<vault>/OLC/Projects/<project_id>/{index.md, current-state.md, decisions/, tasks/, logs/, memory/, taste/}`
|
|
100
|
+
- `<vault>/OLC/registry.json` — `{ projects: { "<id>": { repoRoot } } }` entry for this repo.
|
|
101
|
+
|
|
102
|
+
Vault path precedence: explicit `vaultPath` > `OLC_VAULT_PATH` env > existing config. OLC never invents a vault location — missing path returns `needs-decision`, never a silent default.
|
|
103
|
+
|
|
104
|
+
Re-running init is always safe: run it again after pulling updates; `created` becomes `preserved`. To preview without writing: `initProject({ ..., dryRun: true })`.
|
|
105
|
+
|
|
106
|
+
## Updating
|
|
107
|
+
|
|
108
|
+
1. `git pull` the OLC checkout.
|
|
109
|
+
2. `npm ci && npm run build && npm test`.
|
|
110
|
+
3. Re-run init for each consuming project (creates only missing files; your vault notes, checkpoints, and taste rules are untouched).
|
|
111
|
+
|
|
112
|
+
No migration step exists yet — templates live in the package (`templates/`); old vault documents are never auto-migrated.
|
|
113
|
+
|
|
114
|
+
## Uninstalling
|
|
115
|
+
|
|
116
|
+
Per consuming project:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
# 1. Remove OLC resources from the project
|
|
120
|
+
rm -rf .opencode/agents/olc-plan.md .opencode/agents/olc-build.md \
|
|
121
|
+
.opencode/skills/olc-explore .olc
|
|
122
|
+
# 2. Remove the plugin entry from opencode.json ("plugin": ["file:///..."])
|
|
123
|
+
# 3. Optionally remove the vault scope (YOUR NOTES — back up first):
|
|
124
|
+
# rm -rf "$VAULT/OLC/Projects/<project_id>"
|
|
125
|
+
# 4. Optionally remove the registry entry in "$VAULT/OLC/registry.json"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
No global state, no daemons, no background processes — nothing else to clean up.
|
|
129
|
+
|
|
130
|
+
## Security notes
|
|
131
|
+
|
|
132
|
+
- **Never store secrets in `.olc/config.json`** — credential-looking keys are rejected at parse time. Use env vars or a secret manager.
|
|
133
|
+
- **Memory/log writes are secret-scrubbed** (`src/log/index.ts`): known token/key patterns become `[redacted]` before reaching the vault. The scrub list is documented and minimal — treat it as a safety net, not a vault for secrets.
|
|
134
|
+
- **Git safety**: checkpoints stage only explicit OLC-owned paths (`git add -- <paths>`) and commit with a pathspec. `git add .`/`-A`, plain `git commit`, `reset --hard`, and force-push are banned in OLC flows. Ambiguous ownership aborts and asks you.
|
|
135
|
+
- **Wrong-project protection**: every read/write validates `project_id` → repo-root → vault registration first (`validateIdentity`). Mismatches block with zero writes.
|
|
136
|
+
|
|
137
|
+
## Troubleshooting
|
|
138
|
+
|
|
139
|
+
| Symptom | Cause / fix |
|
|
140
|
+
|---------|-------------|
|
|
141
|
+
| `project_id "x" is not registered` | Run init for this repo, or you are in the wrong checkout. |
|
|
142
|
+
| `Refusing to touch the wrong project's memory` | `project_id` maps to a different repo root. Use a new `projectId` for this checkout or move to the registered repo. |
|
|
143
|
+
| `No vault path configured` | Pass `vaultPath` or set `OLC_VAULT_PATH`. OLC never guesses. |
|
|
144
|
+
| Plugin not listed by `/api/plugin` | Check the `file://` path in `opencode.json` points at the OLC checkout root (containing `dist/`). Rebuild (`npm run build`) — the entrypoint is compiled output. |
|
|
145
|
+
| Agent/skill not discovered | Files must be at `.opencode/agents/<name>.md` / `.opencode/skills/<id>/SKILL.md` relative to the project dir you pass in `location`. Check frontmatter has `description`. |
|
|
146
|
+
| `Detached HEAD` / `SESSION_DRIFT` | Confirm branch + task before continuing — nothing was switched or closed. |
|
|
147
|
+
| `OWNED_PATH_PRESTAGED` / `FOREIGN_EDIT` on checkpoint | Someone (you or a tool) touched OLC-owned files outside the task. Unstage / reconcile, then retry. |
|
|
148
|
+
|
|
149
|
+
## Docs map
|
|
150
|
+
|
|
151
|
+
- `docs/PRD.md` — requirements (source of truth for *what*).
|
|
152
|
+
- `docs/TASKS.md` — task board with verification evidence (source of truth for *status*).
|
|
153
|
+
- `docs/DECISIONS.md` — open technical decisions (#1 name, #3 version pin still open).
|
|
154
|
+
- `AGENTS.md` — working rules for agents in this repo.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: OLC build agent — implements one approved task step at a time with evidence-backed verification
|
|
3
|
+
mode: subagent
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are `olc-build`, the implementation agent of OLC (Obsidian Lean Coder).
|
|
7
|
+
You execute approved plans in small bounded steps. You never expand scope on your own.
|
|
8
|
+
|
|
9
|
+
## Required reading (do this first, every time)
|
|
10
|
+
|
|
11
|
+
1. The project root `AGENTS.md` (OLC working rules).
|
|
12
|
+
2. `docs/PRD.md` (product requirements, source of truth).
|
|
13
|
+
3. The current task entry in `docs/TASKS.md` and the APPROVED `intent.md` + `plan.md`.
|
|
14
|
+
4. The consuming project's `.olc/AGENTS.md` (project-specific instructions).
|
|
15
|
+
|
|
16
|
+
## Preconditions (all must hold, or stop)
|
|
17
|
+
|
|
18
|
+
- The task has an approved plan with bounded acceptance criteria. Missing
|
|
19
|
+
approval or a context mismatch blocks implementation — propose, do not perform.
|
|
20
|
+
- Validate project identity (config `project_id` vs. vault registry and actual
|
|
21
|
+
repo root) before any memory operation. On mismatch, stop with an actionable
|
|
22
|
+
message.
|
|
23
|
+
- Before any Git-sensitive operation, inspect the actual repository root,
|
|
24
|
+
current branch, HEAD, working tree, diff, and untracked files.
|
|
25
|
+
|
|
26
|
+
## Execution rules
|
|
27
|
+
|
|
28
|
+
- Implement ONE approved modular task at a time, within its acceptance criteria.
|
|
29
|
+
- Load only relevant project context. Small technical decisions and fixes inside
|
|
30
|
+
the approved scope are allowed.
|
|
31
|
+
- Scope, product behavior, accepted risks, or architecture changes require user
|
|
32
|
+
approval and a plan revision first. Out-of-scope work is proposed, not performed.
|
|
33
|
+
- Run the smallest meaningful checks (tests, typecheck, lint, build) and record
|
|
34
|
+
exact results. Never fabricate test claims. Retry a fix a bounded number of
|
|
35
|
+
times, then stop and report attempts with evidence and options.
|
|
36
|
+
- Git safety: never run destructive operations (`reset --hard`, force checkout,
|
|
37
|
+
`clean`, branch deletion, force-push) without explicit informed approval. Never
|
|
38
|
+
use `git add .` / `git add -A` for checkpoints — stage explicit paths only.
|
|
39
|
+
Never stage, commit, or discard changes that are not clearly part of the
|
|
40
|
+
current task. If ownership is ambiguous, stop and ask.
|
|
41
|
+
- If blocked, stop, document attempts and evidence, and ask for direction.
|
|
42
|
+
|
|
43
|
+
## Closeout
|
|
44
|
+
|
|
45
|
+
End every session with a plain-language summary: what changed, observed result,
|
|
46
|
+
tests/checks run with outcomes, what remains or is blocked, the next suggested
|
|
47
|
+
task, and any checkpoint commit reference.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: OLC planning agent — investigates a task and writes intent.md + plan.md without touching app source
|
|
3
|
+
mode: subagent
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are `olc-plan`, the planning agent of OLC (Obsidian Lean Coder).
|
|
7
|
+
You extend the default planning behavior: investigate first, write the plan down, never code.
|
|
8
|
+
|
|
9
|
+
## Required reading (do this first, every time)
|
|
10
|
+
|
|
11
|
+
1. The project root `AGENTS.md` (OLC working rules).
|
|
12
|
+
2. `docs/PRD.md` (product requirements, source of truth).
|
|
13
|
+
3. The current task entry in `docs/TASKS.md` (goal, scope, acceptance criteria).
|
|
14
|
+
4. The consuming project's `.olc/AGENTS.md` (project-specific instructions).
|
|
15
|
+
|
|
16
|
+
If any of these is missing or the task scope is unclear, stop and ask one focused
|
|
17
|
+
question instead of guessing.
|
|
18
|
+
|
|
19
|
+
## Investigation
|
|
20
|
+
|
|
21
|
+
- Inspect the actual repository source and Git state (`git status`, branch, log)
|
|
22
|
+
before proposing anything. Cite file paths and evidence.
|
|
23
|
+
- Offer both Explore and direct Plan modes; recommend one based on complexity,
|
|
24
|
+
but let the user choose.
|
|
25
|
+
|
|
26
|
+
## Hard boundaries
|
|
27
|
+
|
|
28
|
+
- You MUST NOT modify application source files. No edits, no new source files,
|
|
29
|
+
no dependency changes, no migrations. Reading is always allowed.
|
|
30
|
+
- The only files you may write are OLC planning documents inside the configured
|
|
31
|
+
vault (`intent.md`, `plan.md`, plus an explore report when Explore is used).
|
|
32
|
+
- You MUST validate project identity (config `project_id` vs. vault registry)
|
|
33
|
+
before reading or writing any memory. On mismatch, stop with an actionable
|
|
34
|
+
message. Never invent a fallback location.
|
|
35
|
+
- Produce/revise `intent.md` and `plan.md` together. Keep what/why (intent)
|
|
36
|
+
separate from how (plan).
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
|
|
40
|
+
- Write `intent.md` and `plan.md` for the task, with modular steps, per-step
|
|
41
|
+
expected results, acceptance criteria, tests, dependencies, risks, and open
|
|
42
|
+
questions.
|
|
43
|
+
- Do NOT start coding, and do not hand off to `olc-build`, before the user has
|
|
44
|
+
explicitly approved both documents.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning approval and scope-change return path (OLC-034).
|
|
3
|
+
*
|
|
4
|
+
* Combines the OLC-032 document gate (both intent.md and plan.md approved)
|
|
5
|
+
* with the OLC-033 registry gate (task status allows implementation), and
|
|
6
|
+
* implements the scope-change loop: an approved task whose scope changes
|
|
7
|
+
* goes back to draft for re-approval instead of silently continuing.
|
|
8
|
+
*
|
|
9
|
+
* - `assertBuildReady`: build gate — registry status must be `approved` or
|
|
10
|
+
* `in_progress` AND both docs must be `approved`. Anything else throws.
|
|
11
|
+
* - `requestScopeChange`: park an approved/in-progress task for revision.
|
|
12
|
+
* Registry moves `approved → draft` or `in_progress → review` (both are
|
|
13
|
+
* table-legal per OLC-033); docs are revised WITHOUT body changes, so
|
|
14
|
+
* statuses flip back to `draft` and re-approval becomes mandatory.
|
|
15
|
+
* History records the reason plus a reminder that a safe code checkpoint
|
|
16
|
+
* (OLC-051 flow) is required before continuing impacted work.
|
|
17
|
+
* - `resumeAfterRevision`: explicit re-entry after re-approval — approves
|
|
18
|
+
* the docs again and moves the registry `draft → approved` or
|
|
19
|
+
* `review → in_progress`. Nothing resumes implicitly.
|
|
20
|
+
*/
|
|
21
|
+
import { type TaskStatus } from "../tasks/index.js";
|
|
22
|
+
export type ApprovalErrorCode = "NOT_APPROVED" | "INVALID_STATE";
|
|
23
|
+
export declare class ApprovalError extends Error {
|
|
24
|
+
readonly code: ApprovalErrorCode;
|
|
25
|
+
constructor(code: ApprovalErrorCode, message: string);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build gate: throws unless the task is registered with a buildable
|
|
29
|
+
* registry status AND both planning docs are approved. Call before any
|
|
30
|
+
* implementation work (this is the cross-check OLC-033 left open).
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertBuildReady(vaultRoot: string, projectId: string, taskId: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Park a build-ready task for scope revision. Only `approved` and
|
|
35
|
+
* `in_progress` tasks can enter the scope-change path; anything else is
|
|
36
|
+
* an error (there is no approved scope to change). Doc bodies are never
|
|
37
|
+
* touched — only statuses flip to `draft`, so re-approval is mandatory
|
|
38
|
+
* and the approved plan cannot be silently replaced.
|
|
39
|
+
*/
|
|
40
|
+
export declare function requestScopeChange(vaultRoot: string, projectId: string, taskId: string, reason: string, date: string): {
|
|
41
|
+
registryFrom: TaskStatus;
|
|
42
|
+
registryTo: TaskStatus;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Explicit re-entry after a scope revision: re-approve both docs and move
|
|
46
|
+
* the registry forward (`draft → approved`, `review → in_progress`).
|
|
47
|
+
* Only valid for tasks parked by `requestScopeChange`; anything else is
|
|
48
|
+
* an error. Never runs implicitly.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resumeAfterRevision(vaultRoot: string, projectId: string, taskId: string, date: string): {
|
|
51
|
+
registryFrom: TaskStatus;
|
|
52
|
+
registryTo: TaskStatus;
|
|
53
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning approval and scope-change return path (OLC-034).
|
|
3
|
+
*
|
|
4
|
+
* Combines the OLC-032 document gate (both intent.md and plan.md approved)
|
|
5
|
+
* with the OLC-033 registry gate (task status allows implementation), and
|
|
6
|
+
* implements the scope-change loop: an approved task whose scope changes
|
|
7
|
+
* goes back to draft for re-approval instead of silently continuing.
|
|
8
|
+
*
|
|
9
|
+
* - `assertBuildReady`: build gate — registry status must be `approved` or
|
|
10
|
+
* `in_progress` AND both docs must be `approved`. Anything else throws.
|
|
11
|
+
* - `requestScopeChange`: park an approved/in-progress task for revision.
|
|
12
|
+
* Registry moves `approved → draft` or `in_progress → review` (both are
|
|
13
|
+
* table-legal per OLC-033); docs are revised WITHOUT body changes, so
|
|
14
|
+
* statuses flip back to `draft` and re-approval becomes mandatory.
|
|
15
|
+
* History records the reason plus a reminder that a safe code checkpoint
|
|
16
|
+
* (OLC-051 flow) is required before continuing impacted work.
|
|
17
|
+
* - `resumeAfterRevision`: explicit re-entry after re-approval — approves
|
|
18
|
+
* the docs again and moves the registry `draft → approved` or
|
|
19
|
+
* `review → in_progress`. Nothing resumes implicitly.
|
|
20
|
+
*/
|
|
21
|
+
import { PlanningError, approveTaskDocs, assertApproved, reviseTaskDocs, } from "../planning/index.js";
|
|
22
|
+
import { TaskRegistryError, getTask, setTaskStatus, } from "../tasks/index.js";
|
|
23
|
+
export class ApprovalError extends Error {
|
|
24
|
+
code;
|
|
25
|
+
constructor(code, message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "ApprovalError";
|
|
28
|
+
this.code = code;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Registry statuses under which implementation work may proceed (docs permitting). */
|
|
32
|
+
const BUILDABLE_STATUSES = ["approved", "in_progress"];
|
|
33
|
+
/**
|
|
34
|
+
* Build gate: throws unless the task is registered with a buildable
|
|
35
|
+
* registry status AND both planning docs are approved. Call before any
|
|
36
|
+
* implementation work (this is the cross-check OLC-033 left open).
|
|
37
|
+
*/
|
|
38
|
+
export function assertBuildReady(vaultRoot, projectId, taskId) {
|
|
39
|
+
const entry = getTask(vaultRoot, projectId, taskId);
|
|
40
|
+
if (!entry) {
|
|
41
|
+
throw new ApprovalError("NOT_APPROVED", `Task ${taskId} is not registered. Register it, draft intent.md/plan.md, and get them approved before coding.`);
|
|
42
|
+
}
|
|
43
|
+
if (!BUILDABLE_STATUSES.includes(entry.status)) {
|
|
44
|
+
throw new ApprovalError("NOT_APPROVED", `Task ${taskId} is not approved for implementation: registry status is ${entry.status} ` +
|
|
45
|
+
`(needs approved or in_progress). Move it through the transition table first.`);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
assertApproved(vaultRoot, projectId, taskId);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error instanceof PlanningError) {
|
|
52
|
+
throw new ApprovalError("NOT_APPROVED", error.message);
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Park a build-ready task for scope revision. Only `approved` and
|
|
59
|
+
* `in_progress` tasks can enter the scope-change path; anything else is
|
|
60
|
+
* an error (there is no approved scope to change). Doc bodies are never
|
|
61
|
+
* touched — only statuses flip to `draft`, so re-approval is mandatory
|
|
62
|
+
* and the approved plan cannot be silently replaced.
|
|
63
|
+
*/
|
|
64
|
+
export function requestScopeChange(vaultRoot, projectId, taskId, reason, date) {
|
|
65
|
+
const entry = getTask(vaultRoot, projectId, taskId);
|
|
66
|
+
if (!entry) {
|
|
67
|
+
throw new ApprovalError("INVALID_STATE", `Cannot request a scope change for unknown task ${taskId}. Register and approve it first.`);
|
|
68
|
+
}
|
|
69
|
+
if (entry.status !== "approved" && entry.status !== "in_progress") {
|
|
70
|
+
throw new ApprovalError("INVALID_STATE", `Cannot request a scope change for task ${taskId}: registry status is ${entry.status}, ` +
|
|
71
|
+
"not approved or in_progress. There is no approved scope to change — revise the draft instead.");
|
|
72
|
+
}
|
|
73
|
+
// Docs must currently be approved, otherwise the task is already parked.
|
|
74
|
+
try {
|
|
75
|
+
assertApproved(vaultRoot, projectId, taskId);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error instanceof PlanningError) {
|
|
79
|
+
throw new ApprovalError("INVALID_STATE", `Task ${taskId} is already parked for revision (${error.message}). Re-approve the docs instead of opening another scope change.`);
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
const registryTo = entry.status === "approved" ? "draft" : "review";
|
|
84
|
+
try {
|
|
85
|
+
setTaskStatus(vaultRoot, projectId, taskId, registryTo, date);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof TaskRegistryError) {
|
|
89
|
+
throw new ApprovalError("INVALID_STATE", error.message);
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
reviseTaskDocs(vaultRoot, projectId, taskId, `SCOPE CHANGE requested: ${reason}\n\nSafe code checkpoint of current progress is required (OLC-051 flow) before continuing impacted work. Re-approval of both documents is mandatory.`, date);
|
|
94
|
+
return { registryFrom: entry.status, registryTo };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Explicit re-entry after a scope revision: re-approve both docs and move
|
|
98
|
+
* the registry forward (`draft → approved`, `review → in_progress`).
|
|
99
|
+
* Only valid for tasks parked by `requestScopeChange`; anything else is
|
|
100
|
+
* an error. Never runs implicitly.
|
|
101
|
+
*/
|
|
102
|
+
export function resumeAfterRevision(vaultRoot, projectId, taskId, date) {
|
|
103
|
+
const entry = getTask(vaultRoot, projectId, taskId);
|
|
104
|
+
if (!entry) {
|
|
105
|
+
throw new ApprovalError("INVALID_STATE", `Cannot resume unknown task ${taskId}. Register it first.`);
|
|
106
|
+
}
|
|
107
|
+
const registryTo = entry.status === "draft" ? "approved" : entry.status === "review" ? "in_progress" : null;
|
|
108
|
+
if (registryTo === null) {
|
|
109
|
+
throw new ApprovalError("INVALID_STATE", `Task ${taskId} is not parked for revision (registry status ${entry.status}). ` +
|
|
110
|
+
"Only draft (from approved) or review (from in_progress) tasks parked by a scope change can resume here.");
|
|
111
|
+
}
|
|
112
|
+
approveTaskDocs(vaultRoot, projectId, taskId, date);
|
|
113
|
+
try {
|
|
114
|
+
setTaskStatus(vaultRoot, projectId, taskId, registryTo, date);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof TaskRegistryError) {
|
|
118
|
+
throw new ApprovalError("INVALID_STATE", error.message);
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
return { registryFrom: entry.status, registryTo };
|
|
123
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OLC-040 — bounded `olc-build` task execution frame.
|
|
3
|
+
*
|
|
4
|
+
* The agent does the coding; this module enforces the bounds:
|
|
5
|
+
* 1. `beginTask` — identity (OLC-021, via the loaded OLC-020 config) and the
|
|
6
|
+
* approval gate (OLC-034) must pass, otherwise implementation is blocked
|
|
7
|
+
* before it starts. Returns a frame carrying ONLY the approved task's
|
|
8
|
+
* context (intent/plan bodies), never the whole vault. The caller declares
|
|
9
|
+
* which repo-relative paths it will touch; the registry task moves
|
|
10
|
+
* approved→in_progress.
|
|
11
|
+
* 2. `recordDecision` — small in-scope technical decisions go to history.md.
|
|
12
|
+
* 3. `completeTask` — identity re-checked, then the working tree is diffed:
|
|
13
|
+
* any change outside the declared paths throws SCOPE_CHANGED (out-of-scope
|
|
14
|
+
* work is proposed via the error, not performed). Clean frames move the
|
|
15
|
+
* registry task in_progress→review.
|
|
16
|
+
*
|
|
17
|
+
* Git access here is deliberately minimal (HEAD sha + porcelain status);
|
|
18
|
+
* the full inspection module is OLC-051's job and may consolidate these.
|
|
19
|
+
*/
|
|
20
|
+
import type { ResolvedConfig } from "../config/index.js";
|
|
21
|
+
export type BuildErrorCode = "NOT_READY" | "CONTEXT_MISMATCH" | "SCOPE_CHANGED" | "NO_TASK";
|
|
22
|
+
export declare class BuildError extends Error {
|
|
23
|
+
readonly code: BuildErrorCode;
|
|
24
|
+
readonly details?: string[];
|
|
25
|
+
constructor(code: BuildErrorCode, message: string, details?: string[]);
|
|
26
|
+
}
|
|
27
|
+
export interface BeginTaskInput {
|
|
28
|
+
/** Loaded + vault-resolved project config (OLC-020). */
|
|
29
|
+
config: ResolvedConfig;
|
|
30
|
+
taskId: string;
|
|
31
|
+
/** Repo-relative paths the implementation may touch. Empty = docs-only task. */
|
|
32
|
+
touchPaths?: string[];
|
|
33
|
+
/** Directory inside the project repo (identity is checked from here). */
|
|
34
|
+
startDir?: string;
|
|
35
|
+
/** Override for today (tests); defaults to current UTC date. */
|
|
36
|
+
date?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface BuildFrame {
|
|
39
|
+
taskId: string;
|
|
40
|
+
intentBody: string;
|
|
41
|
+
planBody: string;
|
|
42
|
+
declaredPaths: string[];
|
|
43
|
+
baseHead: string;
|
|
44
|
+
startedAt: string;
|
|
45
|
+
}
|
|
46
|
+
/** Repo-relative changed paths (staged + unstaged + untracked) vs current HEAD. */
|
|
47
|
+
export declare function changedPaths(projectRoot: string): string[];
|
|
48
|
+
export declare function beginTask(input: BeginTaskInput): BuildFrame;
|
|
49
|
+
export declare function recordDecision(frame: Pick<BuildFrame, "taskId">, config: ResolvedConfig, text: string, date?: string): void;
|
|
50
|
+
export declare function completeTask(frame: BuildFrame, config: ResolvedConfig, repoRoot: string, date?: string): {
|
|
51
|
+
changed: string[];
|
|
52
|
+
};
|