@jualopezmo/codeforge 0.4.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.
- package/LICENSE +21 -0
- package/README.md +368 -0
- package/VERSION +1 -0
- package/bin/codeforge.mjs +64 -0
- package/install.ps1 +317 -0
- package/install.sh +326 -0
- package/package.json +39 -0
- package/src/CLAUDE.md +88 -0
- package/src/CONTINUITY.template.md +16 -0
- package/src/PROJECT.template.md +27 -0
- package/src/configs/claude/settings.json +6 -0
- package/src/configs/codex/config.toml +17 -0
- package/src/configs/opencode.json +14 -0
- package/src/docs/CHANGELOG.md +9 -0
- package/src/docs/adr/.gitkeep +0 -0
- package/src/docs/e2e/reports/.gitkeep +0 -0
- package/src/docs/e2e/use-cases/.gitkeep +0 -0
- package/src/docs/extending.md +134 -0
- package/src/docs/plans/.gitkeep +0 -0
- package/src/docs/prds/.gitkeep +0 -0
- package/src/docs/research/.gitkeep +0 -0
- package/src/docs/solutions/.gitkeep +0 -0
- package/src/shared/rules/approach-comparison.md +29 -0
- package/src/shared/rules/continuity.md +32 -0
- package/src/shared/rules/docs-layout.md +23 -0
- package/src/shared/rules/memory.md +34 -0
- package/src/shared/rules/models.md +59 -0
- package/src/shared/rules/project-rules.md +31 -0
- package/src/shared/rules/research.md +30 -0
- package/src/shared/rules/severity.md +17 -0
- package/src/shared/rules/ship-gates.md +164 -0
- package/src/shared/rules/tdd.md +20 -0
- package/src/shared/rules/workflow.md +38 -0
- package/src/shared/scripts/check-gates.ps1 +197 -0
- package/src/shared/scripts/check-gates.sh +201 -0
- package/src/shared/scripts/claude-gate-hook.ps1 +35 -0
- package/src/shared/scripts/claude-gate-hook.sh +43 -0
- package/src/shared/state.template.md +33 -0
- package/src/skills/adr/SKILL.md +63 -0
- package/src/skills/checkpoint/SKILL.md +50 -0
- package/src/skills/council/SKILL.md +87 -0
- package/src/skills/finish-branch/SKILL.md +85 -0
- package/src/skills/fix-bug/SKILL.md +84 -0
- package/src/skills/index/SKILL.md +52 -0
- package/src/skills/new-feature/SKILL.md +84 -0
- package/src/skills/plan/SKILL.md +63 -0
- package/src/skills/prd/SKILL.md +62 -0
- package/src/skills/quick-fix/SKILL.md +60 -0
- package/src/skills/research/SKILL.md +61 -0
- package/src/skills/review/SKILL.md +66 -0
- package/src/skills/simplify/SKILL.md +59 -0
- package/src/skills/verify-e2e/SKILL.md +102 -0
- package/src/sync.ps1 +69 -0
- package/src/sync.sh +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Juan Motta
|
|
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
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# codeforge
|
|
2
|
+
|
|
3
|
+
**One workflow discipline that runs identically on Claude Code, Codex, and OpenCode.**
|
|
4
|
+
|
|
5
|
+
codeforge gives an AI coding agent a consistent, opinionated way of working — research →
|
|
6
|
+
plan → TDD → cross-engine review → verify → ship — plus shared memory and session
|
|
7
|
+
continuity. The discipline is **skills + config first** — no runtime hooks by default. The
|
|
8
|
+
build-time scripts (the installer and the `sync` generator) run outside the agent's turn; a
|
|
9
|
+
couple of small helper scripts ship into the project too (`check-gates`, and the opt-in
|
|
10
|
+
`--with-hooks` gate hook), invoked by the workflow rather than by a default hook. Point any of
|
|
11
|
+
the three CLIs at the project and they pick up the same rules, skills, and guardrails.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
- **Interoperable discipline.** The same workflow works whether you drive with Claude
|
|
18
|
+
Code, Codex, or OpenCode — no per-engine fork to maintain.
|
|
19
|
+
- **Guided workflows** for the common cases: new feature, bug fix, quick fix, PRD,
|
|
20
|
+
research, planning, review, multi-engine council, and branch wrap-up.
|
|
21
|
+
- **Cross-engine review.** The reviewer/advisor always runs on a *different* engine than
|
|
22
|
+
the driver, so you get real model diversity, not an echo chamber.
|
|
23
|
+
- **Portable memory + docs layout.** Solved bugs, decisions (ADRs), plans, and research
|
|
24
|
+
live in the repo so the next session — or the next engine — inherits the context.
|
|
25
|
+
- **Session continuity.** A tiny handoff file lets a fresh session (or a reset context)
|
|
26
|
+
resume exactly where you left off.
|
|
27
|
+
- **Native ship guardrails.** `git push` / `gh pr create` pause for human approval on
|
|
28
|
+
each engine, using its own native config — no custom scripts.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
### One neutral source, generated per engine (no symlinks)
|
|
35
|
+
|
|
36
|
+
The shippable payload is a single **engine-neutral source** in **`src/`** — the
|
|
37
|
+
instructions, skills, rules, and per-engine configs. This source and its generators live in
|
|
38
|
+
the **codeforge repo**; they never travel into a target project. `install.sh` copies only the
|
|
39
|
+
runtime files a target needs and runs a generator (`sync.sh` / `sync.ps1`) that produces each
|
|
40
|
+
engine's config and skills **by plain copy** straight into the target — no symlinks, so it
|
|
41
|
+
works identically on macOS, Linux, and Windows. Editing is centralized: change the neutral
|
|
42
|
+
source in codeforge, then re-run the installer against the target (**thin install** — the
|
|
43
|
+
target gets only what the agent needs at runtime, none of the build machinery).
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
flowchart TD
|
|
47
|
+
subgraph SRC["Neutral source (lives in codeforge, edit here)"]
|
|
48
|
+
INS["CLAUDE.md"]
|
|
49
|
+
SK["skills/<name>/SKILL.md"]
|
|
50
|
+
RU["shared/rules/*.md"]
|
|
51
|
+
CF["configs/claude · configs/codex · configs/opencode"]
|
|
52
|
+
end
|
|
53
|
+
SRC -->|install.sh runs sync --out target| GEN["Generated into the target (committed with the project)"]
|
|
54
|
+
GEN --> CLAUDE["Claude Code<br/>CLAUDE.md · .claude/settings.json · .claude/skills"]
|
|
55
|
+
GEN --> CODEX["Codex<br/>AGENTS.md · .codex/config.toml · .agents/skills"]
|
|
56
|
+
GEN --> OPEN["OpenCode<br/>AGENTS.md · opencode.json · reads .claude/.agents skills"]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- **Neutral source vs generated:** you edit only the neutral source in codeforge (`CLAUDE.md`,
|
|
60
|
+
`skills/`, `shared/rules/`, `configs/`). The per-engine artifacts (`AGENTS.md`,
|
|
61
|
+
`opencode.json`, `.claude/`, `.agents/`, `.codex/`) are **generated into the target and
|
|
62
|
+
committed with it** — so a clone works immediately — but never hand-edited. The target holds
|
|
63
|
+
no source or generator; re-run the installer against it after editing the source.
|
|
64
|
+
- **Instructions:** `CLAUDE.md` is the canonical set. Sync copies it to `AGENTS.md` so Claude
|
|
65
|
+
Code reads `CLAUDE.md` and Codex/OpenCode read `AGENTS.md` — same content, no drift.
|
|
66
|
+
- **Skills:** `skills/` is the single source of truth. Sync copies it into the two paths that
|
|
67
|
+
cover all three engines: `.claude/skills` (Claude Code, also read by OpenCode) and
|
|
68
|
+
`.agents/skills` (Codex, also read by OpenCode). Codex only discovers project skills under
|
|
69
|
+
`.agents/skills` — not `.codex/skills`.
|
|
70
|
+
- **Configs:** `configs/claude/settings.json`, `configs/codex/config.toml`,
|
|
71
|
+
`configs/opencode.json` are the editable gate configs in the codeforge source. Sync places
|
|
72
|
+
each where its engine looks for it in the target (`.claude/settings.json`,
|
|
73
|
+
`.codex/config.toml`, root `opencode.json`) as a generated baseline. Per-project Claude
|
|
74
|
+
overrides go in `.claude/settings.local.json` (gitignored, never touched by the installer).
|
|
75
|
+
- **Rules:** `shared/rules/*.md` hold the discipline (severity, TDD, ship-gates, memory,
|
|
76
|
+
continuity, models, …), read in place and referenced by the skills.
|
|
77
|
+
|
|
78
|
+
> **Why copies, not symlinks?** Duplication is deliberate: symlinks are fragile on Windows
|
|
79
|
+
> and across zip/clone mirrors. One neutral source + a generator gives a single place to
|
|
80
|
+
> edit without ever fighting symlink support.
|
|
81
|
+
|
|
82
|
+
### Enforcement model — honest about what each signal is worth
|
|
83
|
+
|
|
84
|
+
This is **discipline, not a hard gate.** No hook conditionally blocks an action. Be precise
|
|
85
|
+
about the strength of each signal (see [`ship-gates.md`](src/shared/rules/ship-gates.md)):
|
|
86
|
+
|
|
87
|
+
- **Advisory** — the skills *instruct* the agent to pass the gates before shipping.
|
|
88
|
+
- **Attested** — `finish-branch` runs `shared/scripts/check-gates.sh` (`.ps1` on Windows),
|
|
89
|
+
a deterministic Tier-B check that reads `.workflow/state.md` and exits non-zero listing any
|
|
90
|
+
unchecked box. It turns "eyeball the file" into "run a command that fails loudly" — but it
|
|
91
|
+
validates the *record*, not the work (a checked box is a claim), and it only runs when
|
|
92
|
+
invoked.
|
|
93
|
+
- **Verified** — the only signal independent of the agent's say-so: run `check-gates.sh` plus
|
|
94
|
+
your tests **in CI with branch protection**, so the check binds to the exact PR commit
|
|
95
|
+
outside the agent's turn. This is the honest place to put a real gate.
|
|
96
|
+
|
|
97
|
+
On top of that, each engine shows a **best-effort native prompt** on outward actions — it
|
|
98
|
+
reads no gate state and matches by command pattern, so it's bypassable:
|
|
99
|
+
|
|
100
|
+
| Engine | Native prompt | Config |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| Claude Code | `git push` / `gh pr create` are `ask`-tier | `.claude/settings.json` |
|
|
103
|
+
| Codex | `approval_policy` asks when a command crosses the sandbox boundary | `.codex/config.toml` |
|
|
104
|
+
| OpenCode | `git push*` / `gh pr create*` set to `ask` (force-push `deny`) | `opencode.json` |
|
|
105
|
+
|
|
106
|
+
The prompt is a commit-confirmation, **not** proof the gates are green: the approver must run
|
|
107
|
+
`check-gates.sh` or read `.workflow/state.md` first.
|
|
108
|
+
|
|
109
|
+
**Optional hard block (Claude Code only):** `npx @jualopezmo/codeforge --with-hooks` (or
|
|
110
|
+
`install.sh --with-hooks`) installs a Claude Code `PreToolUse` hook — the same `check-gates`
|
|
111
|
+
behind a hook — that **actually blocks** a ship action when the gates are incomplete. It's
|
|
112
|
+
per-developer (written to gitignored `.claude/settings.local.json`), Claude-specific by design
|
|
113
|
+
(so it stays opt-in, off the cross-engine default), and fails open. Codex/OpenCode can do the
|
|
114
|
+
same (Tier C in [`src/docs/extending.md`](src/docs/extending.md)); no adapter ships yet.
|
|
115
|
+
|
|
116
|
+
### Repo layout
|
|
117
|
+
|
|
118
|
+
The payload lives in `src/`, keeping the repo root free of files that would collide when
|
|
119
|
+
working ON codeforge (a root `CLAUDE.md`, `docs/`, etc.). `install.sh` reads `src/` but copies
|
|
120
|
+
only the runtime subset into a target; the source, generators, and seed templates stay here:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
codeforge/
|
|
124
|
+
├── src/ # ── SOURCE (stays in codeforge; only runtime is copied) ──
|
|
125
|
+
│ ├── CLAUDE.md # canonical instructions (copied to the target)
|
|
126
|
+
│ ├── skills/<name>/SKILL.md # canonical skills → generated into .claude/ + .agents/
|
|
127
|
+
│ ├── shared/rules/*.md # discipline: severity, tdd, ship-gates, memory, …
|
|
128
|
+
│ ├── shared/scripts/*.{sh,ps1} # agent-invoked helpers: check-gates, claude-gate-hook (copied)
|
|
129
|
+
│ ├── shared/state.template.md # workflow-state seed (copied to the target)
|
|
130
|
+
│ ├── configs/ # gate-config source → generated engine configs (not copied)
|
|
131
|
+
│ ├── sync.sh · sync.ps1 # the generator (never copied into the target)
|
|
132
|
+
│ ├── docs/extending.md + empty prds/ plans/ research/ solutions/ adr/ # scaffold
|
|
133
|
+
│ └── CONTINUITY.template.md · PROJECT.template.md # seed-only (never copied)
|
|
134
|
+
│
|
|
135
|
+
├── VERSION # single source of truth for the version (→ .forge-version)
|
|
136
|
+
├── bin/codeforge.mjs # npx entry point (wraps the installer) ┐
|
|
137
|
+
├── tools/ # dev-only quality machinery (linter + evals) │ framework only
|
|
138
|
+
├── install.sh · install.ps1 # installers (bash + PowerShell) │ (never copied
|
|
139
|
+
└── package.json · README.md · LICENSE # npm package + docs + license ┘ into a target)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
After a **thin install**, a target project holds only runtime files: the managed
|
|
143
|
+
`CLAUDE.md`, `shared/rules/`, `shared/scripts/`, `shared/state.template.md`, `.forge-version`;
|
|
144
|
+
the project-owned `PROJECT.md`, `CONTINUITY.md`, `docs/`; and the generated engine artifacts —
|
|
145
|
+
`AGENTS.md`, `opencode.json`,
|
|
146
|
+
`.claude/`, `.agents/`, `.codex/`. Committing the generated layer means a fresh clone of the
|
|
147
|
+
project works immediately, with no post-clone step and no dependency on codeforge. There is no
|
|
148
|
+
source or generator in the target — to customize or upgrade, edit the codeforge source and
|
|
149
|
+
re-run the installer against the project. (Only local state — `.workflow/`,
|
|
150
|
+
`.claude/settings.local.json` — is gitignored.) Running an upgrade over a project installed
|
|
151
|
+
by an older, non-thin version cleans up the leftover machinery automatically (`sync.sh`,
|
|
152
|
+
templates, `docs/extending.md` removed; `configs/` and a neutral `skills/` backed up to
|
|
153
|
+
`*.pre-forge.bak`).
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## The workflow
|
|
158
|
+
|
|
159
|
+
```mermaid
|
|
160
|
+
flowchart LR
|
|
161
|
+
prd["prd<br/>(what/why)"] --> research["research<br/>(sourced brief)"]
|
|
162
|
+
research --> plan["plan<br/>(compare + choose)"]
|
|
163
|
+
plan --> build["new-feature / fix-bug<br/>TDD + cross-engine review"]
|
|
164
|
+
build --> finish["finish-branch<br/>verify → commit → push/PR"]
|
|
165
|
+
review["review / council"] -.consulted by.-> plan
|
|
166
|
+
review -.consulted by.-> build
|
|
167
|
+
checkpoint["checkpoint"] -.writes.-> CONT["CONTINUITY.md"]
|
|
168
|
+
CONT -.resumed at session start.-> prd
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Skills
|
|
172
|
+
|
|
173
|
+
| Skill | Purpose |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `prd` | Capture problem/users/goals before designing → `docs/prds/` |
|
|
176
|
+
| `research` | Check current docs + prior art, write a sourced brief → `docs/research/` |
|
|
177
|
+
| `plan` | Clarify intent, compare approaches, write a reviewed plan → `docs/plans/` |
|
|
178
|
+
| `new-feature` | Full feature flow: research → plan → review → TDD → review → verify → ship |
|
|
179
|
+
| `fix-bug` | Systematic debugging: reproduce → root cause → failing test → fix → ship |
|
|
180
|
+
| `quick-fix` | Trivial changes (<3 files); escalates if scope grows |
|
|
181
|
+
| `review` | Cross-engine second opinion on a plan or diff (P0–P3 findings) |
|
|
182
|
+
| `simplify` | Post-green, behavior-preserving cleanup pass (tests stay green) |
|
|
183
|
+
| `verify-e2e` | Execute API/CLI user-journey use cases, write an evidence report, and bind the E2E ship-gate box to it |
|
|
184
|
+
| `council` | Multi-engine advisors → verdict + minority report (hard, expensive forks) |
|
|
185
|
+
| `adr` | Record an architecture decision (context, alternatives, consequences) → `docs/adr/` |
|
|
186
|
+
| `finish-branch` | Confirm gates → final verify → commit → push → PR |
|
|
187
|
+
| `checkpoint` | Write a clean session handoff to `CONTINUITY.md` before closing |
|
|
188
|
+
| `index` | Generate/refresh `docs/index.md` — a high-level project map for fast orientation |
|
|
189
|
+
|
|
190
|
+
### Memory & continuity
|
|
191
|
+
|
|
192
|
+
- **Portable memory (repo-first):** durable knowledge lives in the repo — solved bugs in
|
|
193
|
+
`docs/solutions/`, decisions in `docs/adr/`, history in `docs/CHANGELOG.md` — because
|
|
194
|
+
all three engines read it. Personal per-engine memory is used only where it exists.
|
|
195
|
+
- **Continuity:** `CONTINUITY.md` holds the current focus, the single **Next step**, and
|
|
196
|
+
blockers. Golden rule #1 tells the agent to read it first every session, so a new
|
|
197
|
+
session or a reset context resumes correctly.
|
|
198
|
+
|
|
199
|
+
### Models (cross-engine roles)
|
|
200
|
+
|
|
201
|
+
The reviewer/advisor always runs on a **different engine than the driver** (model diversity is
|
|
202
|
+
the point). The concrete **model IDs, effort, and read-only invocation** for each engine live
|
|
203
|
+
in **one place** — `src/shared/rules/models.md` — so a CLI or model bump is a single-file
|
|
204
|
+
edit; the skills read from there rather than hard-coding commands.
|
|
205
|
+
|
|
206
|
+
`council` consults all three engines at once; `review`/`research` use the non-driver engine.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Installation
|
|
211
|
+
|
|
212
|
+
codeforge is the framework repo — install its discipline into a target project. It's a
|
|
213
|
+
**thin install**: only the agent's runtime files land in the target (the generated engine
|
|
214
|
+
artifacts + a small managed baseline), so a clone of that project works with no dependency on
|
|
215
|
+
codeforge, while all build machinery stays here. With no target argument the installer uses
|
|
216
|
+
the current directory.
|
|
217
|
+
|
|
218
|
+
### Fastest — `npx` (no clone)
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
cd /path/to/your-project
|
|
222
|
+
npx @jualopezmo/codeforge # install into the current directory
|
|
223
|
+
npx @jualopezmo/codeforge --upgrade # refresh framework files later
|
|
224
|
+
npx @jualopezmo/codeforge --version # print the installed codeforge version
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The Node wrapper just runs the platform installer bundled in the package (`sh` / `pwsh`); the
|
|
228
|
+
content it installs is plain markdown + config, and nothing from npm lands in the target beyond
|
|
229
|
+
the same thin payload. Each install stamps `.forge-version` into the target, and a later
|
|
230
|
+
`--upgrade` from a different version prints an advisory. _(Publishing to npm is pending name
|
|
231
|
+
confirmation; until then use the clone method below.)_
|
|
232
|
+
|
|
233
|
+
### From a clone
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# macOS / Linux
|
|
237
|
+
cd /path/to/your-project && /path/to/codeforge/install.sh # install into the current dir
|
|
238
|
+
./install.sh /path/to/your-project # or name the target explicitly
|
|
239
|
+
./install.sh /path/to/your-project --upgrade # refresh framework files later
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```powershell
|
|
243
|
+
# Windows (PowerShell)
|
|
244
|
+
pwsh /path/to/codeforge/install.ps1 # install into the current dir
|
|
245
|
+
pwsh ./install.ps1 C:\path\to\your-project # or name the target explicitly
|
|
246
|
+
pwsh ./install.ps1 C:\path\to\your-project -Upgrade # refresh framework files later
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
What it does:
|
|
250
|
+
|
|
251
|
+
- **Copies the managed runtime baseline** (overwritten on upgrade): `CLAUDE.md`,
|
|
252
|
+
`shared/state.template.md`, the framework's own entries in `shared/rules/` (refreshed **by
|
|
253
|
+
name**), and the docs scaffolding. Your own rules dropped into `shared/rules/` are left
|
|
254
|
+
untouched, so they **survive upgrades**. The source, generators (`sync.sh`/`sync.ps1`),
|
|
255
|
+
`configs/`, and seed templates are **not** copied — they live only in codeforge.
|
|
256
|
+
- **Creates project-owned files only if missing** (never clobbered on re-run): `PROJECT.md`,
|
|
257
|
+
`CONTINUITY.md`, a seed `docs/CHANGELOG.md`. Per-project Claude overrides go in
|
|
258
|
+
`.claude/settings.local.json` (gitignored, never touched).
|
|
259
|
+
- **Generates the engine artifacts** by running `sync --out <target>` (no symlinks):
|
|
260
|
+
`AGENTS.md`, `opencode.json`, and `.claude/`, `.agents/`, `.codex/` (config + skills) as a
|
|
261
|
+
baseline from the codeforge source. These are **committed with the project** (so clones work
|
|
262
|
+
as-is); to change them, edit the codeforge source and re-run the installer.
|
|
263
|
+
- **Self-heals an older, non-thin install** on upgrade: leftover machinery (`sync.sh`,
|
|
264
|
+
`sync.ps1`, root templates, `docs/extending.md`) is removed, and a pre-existing `configs/`
|
|
265
|
+
or neutral `skills/` is backed up to `*.pre-forge.bak` (never silently deleted).
|
|
266
|
+
- An existing `CLAUDE.md` is backed up to `CLAUDE.md.pre-forge.bak` (move its
|
|
267
|
+
project-specifics into `PROJECT.md`), and `.gitignore` is merged, not replaced.
|
|
268
|
+
- Runs a **post-install validation** (skill-discovery paths `.claude`/`.agents`, `AGENTS.md`,
|
|
269
|
+
and engine configs generated) that **exits non-zero** if anything is missing, and warns if
|
|
270
|
+
a config lacks the push/PR gate.
|
|
271
|
+
- **Checks for git.** The workflow (branches, commits) and the ship gates operate on git. If the
|
|
272
|
+
target isn't a repo, the installer **warns** (it never touches your VCS on its own); pass
|
|
273
|
+
`--git-init` to have it run `git init` + a baseline commit for you.
|
|
274
|
+
- **Auto-isolates Claude Code** from ancestor instructions. Codex and OpenCode already scope to
|
|
275
|
+
the project root, but Claude Code walks to the filesystem root and **blends every ancestor
|
|
276
|
+
`CLAUDE.md`/`.claude/rules` into your project**. So if the target sits under a directory that
|
|
277
|
+
has its own `CLAUDE.md` (e.g. a `~/projects/` you keep instructions in), the installer writes
|
|
278
|
+
`claudeMdExcludes` into the gitignored `.claude/settings.local.json` to block those ancestors —
|
|
279
|
+
making the project run its **own** discipline, consistently across all three engines. Pass
|
|
280
|
+
`--no-isolate` to keep inheritance (e.g. an intentional monorepo root). It only manages a
|
|
281
|
+
`settings.local.json` it created; one you own is never touched.
|
|
282
|
+
|
|
283
|
+
Then fill in `PROJECT.md` in the target, edit the neutral source in codeforge as needed
|
|
284
|
+
(`skills/`, `configs/`, `CLAUDE.md`) and re-run the installer against the project, and open
|
|
285
|
+
the project in any of the three engines.
|
|
286
|
+
|
|
287
|
+
> **Windows:** no symlinks are used, so nothing special is required — `install.ps1` and
|
|
288
|
+
> `sync.ps1` are plain PowerShell copies. (Needs PowerShell 7 / `pwsh`.)
|
|
289
|
+
|
|
290
|
+
## How to use it
|
|
291
|
+
|
|
292
|
+
### 1. Open the project in any engine
|
|
293
|
+
|
|
294
|
+
- **Claude Code** — open the folder; `CLAUDE.md` and `.claude/skills/` load automatically.
|
|
295
|
+
- **Codex** — open the folder; `AGENTS.md` and `.agents/skills/` load automatically. Trust
|
|
296
|
+
the project when prompted.
|
|
297
|
+
- **OpenCode** — open the folder; `AGENTS.md` and the skills load automatically;
|
|
298
|
+
`opencode.json` applies the push/PR approval gate.
|
|
299
|
+
|
|
300
|
+
At session start the agent reads `CONTINUITY.md` and resumes from its **Next step**.
|
|
301
|
+
|
|
302
|
+
### 2. Run a workflow
|
|
303
|
+
|
|
304
|
+
Skills load **on demand** — there's no special slash syntax (these are `SKILL.md` skills,
|
|
305
|
+
not slash-commands). Two ways to trigger one, the same across all three engines:
|
|
306
|
+
|
|
307
|
+
- **Implicitly** — just describe the task; the engine matches it to a skill's
|
|
308
|
+
`description` and loads it (e.g. "add a feature that …" → `new-feature`; "there's a bug
|
|
309
|
+
where …" → `fix-bug`).
|
|
310
|
+
- **Explicitly** — name it: *"use the `new-feature` skill"*, *"run `council` on whether to
|
|
311
|
+
do A or B"*, *"`checkpoint` before I stop"*.
|
|
312
|
+
|
|
313
|
+
Per engine, if you want to confirm what's available: ask *"what skills do you have in this
|
|
314
|
+
project?"* — all three list the `skills/` folder. The skill then walks its phases, writes
|
|
315
|
+
artifacts to the right `docs/` folder, and tracks progress in `.workflow/state.md`.
|
|
316
|
+
|
|
317
|
+
### 3. Ship behind the gate
|
|
318
|
+
|
|
319
|
+
Before shipping, the workflow checks that the `.workflow/state.md` gates are green
|
|
320
|
+
(branch, plan reviewed, tests passing, review clean, verified). `git push` / `gh pr create`
|
|
321
|
+
then prompt for approval — approve only when the gates are green.
|
|
322
|
+
|
|
323
|
+
### 4. Close a session cleanly
|
|
324
|
+
|
|
325
|
+
Run **`checkpoint`** before you stop (or when context gets tight). It writes a concrete
|
|
326
|
+
handoff to `CONTINUITY.md` so the next session — same engine or different — picks up
|
|
327
|
+
exactly where you left off.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Project-specific rules
|
|
332
|
+
|
|
333
|
+
Two rule layers apply, both always-on:
|
|
334
|
+
|
|
335
|
+
- **Global baseline** (`CLAUDE.md` golden rules + `shared/rules/*`) — the framework
|
|
336
|
+
discipline, applies without exception.
|
|
337
|
+
- **Project rules** (`PROJECT.md`) — this project's **Persona**, **Project info**,
|
|
338
|
+
**Variables**, and **Special rules**. Editable per project.
|
|
339
|
+
|
|
340
|
+
Project rules **add and refine** (tone, context, variables, special behavior); they never
|
|
341
|
+
override the safety/ship-gate baseline (on conflict, the baseline wins). All three engines
|
|
342
|
+
load `PROJECT.md` via golden rule #2 (OpenCode also force-loads it via `opencode.json`
|
|
343
|
+
`instructions`).
|
|
344
|
+
|
|
345
|
+
**To add project rules:** the installer already seeds `PROJECT.md` in the target — fill the
|
|
346
|
+
four sections and commit. No per-engine config needed. See `shared/rules/project-rules.md`.
|
|
347
|
+
|
|
348
|
+
## Extending
|
|
349
|
+
|
|
350
|
+
See [`src/docs/extending.md`](src/docs/extending.md) — it defines three tiers (skills-only,
|
|
351
|
+
skills + invoked scripts, hooks), a decision checklist, and the steps to add a new skill.
|
|
352
|
+
Most new functionality is a single `skills/<name>/SKILL.md` that all three engines
|
|
353
|
+
discover automatically.
|
|
354
|
+
|
|
355
|
+
## Status
|
|
356
|
+
|
|
357
|
+
**v0.2.0 — quality + distribution.** Verified end-to-end on all three engines — **Claude Code,
|
|
358
|
+
Codex, and OpenCode** — driving a real project. Adds a CI-enforced skill linter + routing
|
|
359
|
+
evals, anti-rationalization anatomy across every skill, a deterministic `check-gates` ship-gate
|
|
360
|
+
validator (with an opt-in Claude Code hard-block via `--with-hooks`), the `adr` and `simplify`
|
|
361
|
+
skills, and `.forge-version` + an `npx @jualopezmo/codeforge` entry point.
|
|
362
|
+
|
|
363
|
+
Engines: Claude Code, Codex, OpenCode. 13 skills, 11 rules. Neutral-source + generator model
|
|
364
|
+
(no symlinks), **thin install** (only runtime lands in the target; machinery stays in codeforge)
|
|
365
|
+
— cross-platform (`install.sh` + `install.ps1`), validated by dry-run install on both bash and
|
|
366
|
+
PowerShell (engine dirs, configs, and `AGENTS.md` generate; bare run targets the cwd; `--upgrade`
|
|
367
|
+
preserves project-owned files and rules and self-heals an older non-thin install; bash↔pwsh
|
|
368
|
+
parity), and by interactive use of the native push/PR gate in each engine.
|
package/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.4.0
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// codeforge — npx entry point. Thin wrapper that runs the platform installer
|
|
3
|
+
// bundled in this package (install.sh on POSIX, install.ps1 on Windows),
|
|
4
|
+
// passing through all arguments. The payload (src/, VERSION) travels in the
|
|
5
|
+
// package, so `npx @jualopezmo/codeforge [target] [--upgrade]` works with no repo clone.
|
|
6
|
+
//
|
|
7
|
+
// npx @jualopezmo/codeforge # install into the current directory
|
|
8
|
+
// npx @jualopezmo/codeforge ./my-project # install into a target
|
|
9
|
+
// npx @jualopezmo/codeforge --upgrade # refresh an existing install
|
|
10
|
+
// npx @jualopezmo/codeforge --version # print the codeforge version
|
|
11
|
+
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { dirname, join } from 'node:path';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { platform } from 'node:os';
|
|
17
|
+
|
|
18
|
+
const pkgRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
|
|
21
|
+
function version() {
|
|
22
|
+
try {
|
|
23
|
+
return readFileSync(join(pkgRoot, 'VERSION'), 'utf8').trim() || 'unknown';
|
|
24
|
+
} catch {
|
|
25
|
+
return 'unknown';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
30
|
+
console.log(version());
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
34
|
+
console.log(`codeforge ${version()} — install the cross-engine workflow discipline into a project.
|
|
35
|
+
|
|
36
|
+
npx @jualopezmo/codeforge [target-dir] [--upgrade] [--with-hooks] [--git-init] [--no-isolate]
|
|
37
|
+
|
|
38
|
+
target-dir where to install (default: current directory)
|
|
39
|
+
--upgrade refresh framework files in an existing install
|
|
40
|
+
--with-hooks also install the opt-in Claude Code hard-block gate hook (Claude only)
|
|
41
|
+
--git-init if the target is not a git repo, initialize one + baseline commit
|
|
42
|
+
--no-isolate keep inheriting ancestor CLAUDE.md (default: auto-isolate via claudeMdExcludes)
|
|
43
|
+
--version print the codeforge version`);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const isWin = platform() === 'win32';
|
|
48
|
+
// Windows: install.ps1 declares PowerShell switches (-Upgrade, ...), not POSIX long-flags,
|
|
49
|
+
// so translate them; an unmapped arg (e.g. the target dir) passes through untouched.
|
|
50
|
+
const winFlag = { '--upgrade': '-Upgrade', '--with-hooks': '-WithHooks', '--git-init': '-GitInit', '--no-isolate': '-NoIsolate' };
|
|
51
|
+
// POSIX: run with `bash`, NOT `sh` — install.sh uses `set -o pipefail`, which dash (the /bin/sh
|
|
52
|
+
// on Debian/Ubuntu) does not support, so `sh install.sh` would abort immediately.
|
|
53
|
+
const cmd = isWin ? 'pwsh' : 'bash';
|
|
54
|
+
const cmdArgs = isWin
|
|
55
|
+
? ['-NoProfile', '-File', join(pkgRoot, 'install.ps1'), ...args.map((a) => winFlag[a] ?? a)]
|
|
56
|
+
: [join(pkgRoot, 'install.sh'), ...args];
|
|
57
|
+
|
|
58
|
+
const r = spawnSync(cmd, cmdArgs, { stdio: 'inherit' });
|
|
59
|
+
if (r.error) {
|
|
60
|
+
const hint = isWin ? 'PowerShell 7 (pwsh) is required on Windows.' : '';
|
|
61
|
+
console.error(`codeforge: could not launch ${cmd}: ${r.error.message}. ${hint}`.trim());
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
process.exit(r.status ?? 1);
|