Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This is the documentation router for Devflow Native.
| OpenCairn split example | [examples/opencairn-parallel-split.md](./examples/opencairn-parallel-split.md) |
| Simple status output example | [examples/simple-status-output.md](./examples/simple-status-output.md) |
| Session list filter examples | [examples/session-list-filters.md](./examples/session-list-filters.md) |
| Repo-local Codex/Claude plugin init skill | [../plugins/devflow/skills/init/SKILL.md](../plugins/devflow/skills/init/SKILL.md) |
| Repo-local Codex plugin start skill | [../plugins/devflow/skills/start/SKILL.md](../plugins/devflow/skills/start/SKILL.md) |
| Repo-local Codex/Claude plugin status skill | [../plugins/devflow/skills/status/SKILL.md](../plugins/devflow/skills/status/SKILL.md) |
| Repo-local Codex/Claude plugin doctor skill | [../plugins/devflow/skills/doctor/SKILL.md](../plugins/devflow/skills/doctor/SKILL.md) |
Expand Down
5 changes: 4 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ packages/cli
devflow harness/init/status/split/finish/doctor/gates/session/review

packages/mcp
devflow.status/devflow.split/devflow.finish/devflow.doctor/devflow.next_prompt/devflow.rewrite_prompt/devflow.sessions_codex/devflow.sessions_attach_plan/devflow.sessions_attach/devflow.sessions_list/devflow.sessions_note tools
devflow.init/status/split/finish/doctor/next_prompt/rewrite_prompt/session/work/review/gate/harness tools

packages/integrations
Claude Code plugin, Codex plugin and MCP config, editor hooks
Expand Down Expand Up @@ -152,6 +152,7 @@ Initial tools:

```text
devflow.status
devflow.init
devflow.split
devflow.finish
devflow.doctor
Expand Down Expand Up @@ -293,6 +294,8 @@ docs/contributing/workflow.md
scripts/project-health.*
.devflow/config.json
.devflow/state/
.github/workflows/devflow.yml
plugins/devflow/
```

## Boundaries
Expand Down
34 changes: 24 additions & 10 deletions docs/contributing/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ This loop should answer three daily questions before larger surfaces exist:

`devflow split` now has a CLI renderer over the core split contract, can read
project-specific split tasks, and can register generated sessions into the
local work item registry. `devflow init` now has a first guarded scaffold implementation:
local work item registry. `devflow init` now has a preset-aware bootstrap path:
without `--confirm`, it renders the plan only; with `--confirm`, it writes the
minimum project contract, sets `review.required` to `true`, and skips existing
files instead of overwriting them. `devflow health` checks those scaffold files
project contract, optional native harness files, optional GitHub CI, inferred
gates, and review policy while skipping existing non-AGENTS files and
augmenting existing `AGENTS.md`. `devflow health` checks those scaffold files
and configured gates.
`devflow gates run` executes one configured gate and records pass/fail
evidence.
Expand Down Expand Up @@ -179,32 +180,45 @@ output for a chosen platform.

Creates or updates a project contract.

The MVP implementation is confirmation-gated:
The implementation is confirmation-gated and preset-aware:

```powershell
devflow init --repo C:\path\to\repo --profile standard --platform windows-powershell --json
devflow init --repo C:\path\to\repo --profile standard --platform windows-powershell --confirm --json
devflow init --preset solo-product --targets codex,claude --ci github --review required --json
devflow init --preset solo-product --targets codex,claude --ci github --review required --confirm --json
```

Inputs:

- profile
- preset: `solo-product`, `research`, or `content-site`
- platform
- native targets: `codex`, `claude`
- CI provider: `github`
- review mode: `required` or `optional`
- docs template
- gate profile
- inferred gate profile from package scripts

Outputs:

- `AGENTS.md`
- `AGENTS.md` Devflow section append when the file already exists
- docs router
- architecture maps
- testing strategy
- `.devflow/config.json`

The generated `.devflow/config.json` enables `review.required` by default so a
newly initialized repo gets the strict review loop immediately. The generated
workflow notes point agents through `devflow review request`, `devflow review
record`, and then `devflow finish`.
- optional `plugins/devflow/*` native harness files
- optional `.github/workflows/devflow.yml`

The generated `.devflow/config.json` records the chosen preset, platform,
review policy, and inferred gates. `solo-product` enables
`review.required` by default. `research` and `content-site` default to
risk-based or direct-docs-main policy unless `--review required` is passed.
The generated workflow notes point agents through `devflow review request`,
`devflow review record`, and then `devflow finish` when review is required.
Native harness files use the same canonical contents as `devflow harness
install`, and the generated init skill is a thin wrapper over the CLI.

Safety rules:

Expand Down
22 changes: 20 additions & 2 deletions docs/harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,19 @@ to publish the latest handoff.

## Harness Commands

The harness command group is the install and repair surface for existing repos.
It should adopt mature repositories instead of blindly scaffolding over them.
`devflow init` is the bootstrap surface for new repositories or repositories
that want a full Devflow project contract in one step. It can write preset
policy, `.devflow/config.json`, `AGENTS.md`, docs, inferred gates, GitHub CI,
and native Codex/Claude plugin files:

```text
devflow init --preset solo-product --targets codex,claude --ci github --review required
devflow init --preset solo-product --targets codex,claude --ci github --review required --confirm
```

The harness command group remains the install and repair surface for existing
repos. It should adopt mature repositories instead of blindly scaffolding over
them.

```text
devflow harness inspect --targets codex,claude,superpowers,codegraph
Expand Down Expand Up @@ -224,6 +235,13 @@ missing `review.required` config that can be merged without dropping existing
gates. Project instructions and gate definitions are reported but not rewritten
automatically.

The Devflow init skill is intentionally a thin wrapper over this CLI behavior.
It chooses `solo-product`, `research`, or `content-site`, runs a dry-run
`devflow init` command, explains the plan, runs `--confirm` only when requested,
then verifies with `devflow health` and `devflow harness health` when native
targets were installed. Policy and file generation stay in Devflow core so
Codex, Claude, shell sessions, and future hosts reproduce the same bootstrap.

## Install UX

The public README should not lead with "run npm install" as the main user
Expand Down
25 changes: 16 additions & 9 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,20 @@ Exit criteria:
- a new repo can get a complete development workflow scaffold
- health status can detect missing docs, workflow files, and malformed gates

Current implementation note: `devflow init` has a first confirmation-gated
scaffold path. The CLI renders a scaffold plan by default and writes
`.devflow/config.json`, `AGENTS.md`, docs router, workflow, testing strategy,
and architecture map index only with `--confirm`, skipping existing files
instead of overwriting them. `devflow health` and MCP `devflow.health` can now
report missing scaffold files, configured gates, and invalid gate definitions
with missing ids, missing commands, or duplicate ids. Template customization
remains later Phase 2 work.
Current implementation note: `devflow init` has a confirmation-gated bootstrap
path. The CLI renders a scaffold plan by default and writes only with
`--confirm`. It supports `--preset solo-product|research|content-site`,
`--targets codex,claude`, `--ci github`, and `--review required|optional`.
It writes `.devflow/config.json`, `AGENTS.md`, docs router, workflow, testing
strategy, architecture map index, optional GitHub Actions workflow, and optional
canonical `plugins/devflow/*` native harness files. Existing non-AGENTS files
are skipped; existing `AGENTS.md` files are augmented with a Devflow section.
Gate definitions are inferred from conservative package scripts such as
`docs:check`, `lint`, `test`, `build`, `bench`, and `links:check`. `devflow
health` and MCP `devflow.health` can now report missing scaffold files,
configured gates, and invalid gate definitions with missing ids, missing
commands, or duplicate ids. Richer custom template packs remain later Phase 2
work.

Current implementation note: `devflow harness inspect --targets
codex,claude,superpowers,codegraph` reports native plugin readiness, MCP launch
Expand Down Expand Up @@ -193,6 +199,7 @@ Build:
- local Devflow MCP server
- `devflow.doctor` MCP tool
- `devflow.status` MCP tool
- `devflow.init` MCP tool
- `devflow.harness_inspect` MCP tool
- `devflow.harness_plan` MCP tool
- `devflow.harness_health` MCP tool
Expand Down Expand Up @@ -234,7 +241,7 @@ Exit criteria:
- plugin/slash-command UX calls the same core contracts as the CLI

Current implementation note: `packages/mcp` has testable handler functions for
`devflow.status`, `devflow.harness_inspect`, `devflow.harness_plan`,
`devflow.status`, `devflow.init`, `devflow.harness_inspect`, `devflow.harness_plan`,
`devflow.harness_health`, `devflow.harness_smoke`, confirmed-write
`devflow.harness_repair`, `devflow.split`, `devflow.explain_term`,
`devflow.doctor`, `devflow.finish`, `devflow.record_gate`, `devflow.gates_run`,
Expand Down
30 changes: 18 additions & 12 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,21 @@ packages/cli/
- `devflow mistakes list`
- `devflow mistakes detect`

`devflow init` currently renders a scaffold plan by default and writes the
minimum project contract only when `--confirm` is provided. The first scaffold
includes `.devflow/config.json`, `AGENTS.md`, a docs router, workflow notes,
testing strategy, and an architecture map index. It also sets
`review.required` to `true` and points workflow notes through `devflow review
request`, `devflow review record`, and `devflow finish`. Existing files are
skipped instead of overwritten. `devflow health` checks that the same scaffold
files and at least one configured gate are present. `devflow harness inspect` reports
`devflow init` renders a scaffold plan by default and writes only when
`--confirm` is provided. It now supports `--preset solo-product|research|content-site`,
`--targets codex,claude`, `--ci github`, and `--review required|optional`.
The scaffold includes `.devflow/config.json`, `AGENTS.md`, a docs router,
workflow notes, testing strategy, and an architecture map index. With native
targets, it also installs canonical `plugins/devflow/*` files for Codex and
Claude and ignores them as local harness files unless `--repo-visible` is
passed. With `--ci github`, it creates `.github/workflows/devflow.yml` from
inferred package scripts. `AGENTS.md` is appended with a Devflow section when
it already exists instead of being replaced. `solo-product` defaults to
`review.required: true`; `research` and `content-site` default to risk-based
or direct-docs-main review policy unless `--review required` is passed. Existing
non-AGENTS files are skipped instead of overwritten. `devflow health` checks
that the same scaffold files and at least one configured gate are present.
`devflow harness inspect` reports
native Codex and Claude Code readiness, MCP config presence, instruction files,
Superpowers signals, CodeGraph-style provider signals, configured gates, and
the smallest install or repair recommendations without writing files.
Expand Down Expand Up @@ -148,10 +155,9 @@ filtered by `--agent <name>`, `--work <id>`, `--since <iso-date>`, sorted by
unchanged. Use `--json` for the stable agent contract or omit it for a short
terminal summary with active filters, attached session ids, changed-file counts,
observed times, limit totals, sort choice, or manual note summaries. The text
summary also surfaces a compact warning count when local state has warnings. `devflow
sessions note` records manual or external session context as local state. The
future `devflow init` command can reuse the same rendering and config
infrastructure once the MVP loop is stable.
summary also surfaces a compact warning count when local state has warnings.
`devflow sessions note` records manual or external session context as local
state.

`devflow finish --json` returns a false-completion guard contract in addition
to the original evidence summary. It reads configured gates from
Expand Down
31 changes: 29 additions & 2 deletions packages/cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,41 @@ try {
async function renderInit(argsForCommand) {
const options = parseOptions(argsForCommand);
const repoPath = options.repo ?? cwd();
const packageJson = await readPackageJson(repoPath);
const plan = createInitPlan({
repo: repoPath,
profile: options.profile,
preset: options.preset,
platform: options.platform ?? defaultPlatformName(),
targets: parseTargetList(options.targets),
ci: options.ci,
review: options.review,
packageJson,
});

if (options.confirm) {
const result = await writeInitPlan(repoPath, plan, { confirmed: true });
const result = await writeInitPlan(repoPath, plan, {
confirmed: true,
repoVisible: options["repo-visible"],
});
render({ ...plan, result }, options.json);
return;
}

render(plan, options.json);
}

async function readPackageJson(repoPath) {
try {
return JSON.parse(await readFile(join(repoPath, "package.json"), "utf8"));
} catch (error) {
if (error.code === "ENOENT" || error instanceof SyntaxError) {
return null;
}
throw error;
}
}

async function renderHealth(argsForCommand) {
const options = parseOptions(argsForCommand);
const repoPath = options.repo ?? cwd();
Expand Down Expand Up @@ -1224,6 +1244,13 @@ function readPackageVersion() {

function renderHelp(group) {
const groups = {
init: [
"devflow init [--json]",
"devflow init --preset solo-product --targets codex,claude --ci github --review required [--json]",
"devflow init --preset solo-product --targets codex,claude --ci github --review required --confirm [--json]",
"devflow init --preset research --review optional [--json]",
"devflow init --preset content-site --ci github [--json]",
],
harness: [
"devflow harness inspect [--json]",
"devflow harness plan [--json]",
Expand Down Expand Up @@ -1301,7 +1328,7 @@ function renderHelp(group) {
" node packages/cli/src/index.js harness health",
"",
"Core commands:",
" init Plan or write a .devflow project scaffold",
" init Plan or write a preset-based Devflow project bootstrap",
" health Check the project scaffold",
" doctor Inspect local shell/tooling rules",
" mistakes <command> Record and detect repeated agent mistake memory",
Expand Down
66 changes: 65 additions & 1 deletion packages/cli/test/cli-mvp.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,70 @@ test("CLI init --confirm writes the minimum project scaffold", async () => {
assert.equal(config.review.required, true);
});

test("CLI init --confirm writes preset bootstrap files for native agents and github ci", async () => {
const repoPath = await createTempGitRepo();
await writeFile(
join(repoPath, "package.json"),
`${JSON.stringify(
{
scripts: {
"docs:check": "node scripts/check-doc-links.mjs",
lint: "eslint .",
test: "node --test",
build: "vite build",
},
},
null,
2,
)}\n`,
"utf8",
);

const { stdout } = await execFileAsync("node", [
"packages/cli/src/index.js",
"init",
"--repo",
repoPath,
"--preset",
"solo-product",
"--targets",
"codex,claude",
"--ci",
"github",
"--review",
"required",
"--confirm",
"--json",
]);
const parsed = JSON.parse(stdout);
const config = JSON.parse(await readFile(join(repoPath, ".devflow", "config.json"), "utf8"));
const agents = await readFile(join(repoPath, "AGENTS.md"), "utf8");
const workflow = await readFile(join(repoPath, ".github", "workflows", "devflow.yml"), "utf8");
const initSkill = await readFile(join(repoPath, "plugins", "devflow", "skills", "init", "SKILL.md"), "utf8");
const initCommand = await readFile(join(repoPath, "plugins", "devflow", "commands", "init.md"), "utf8");
const codexManifest = JSON.parse(await readFile(join(repoPath, "plugins", "devflow", ".codex-plugin", "plugin.json"), "utf8"));
const claudeManifest = JSON.parse(await readFile(join(repoPath, "plugins", "devflow", ".claude-plugin", "plugin.json"), "utf8"));
const gitignore = await readFile(join(repoPath, ".gitignore"), "utf8");

assert.equal(parsed.preset, "solo-product");
assert.equal(parsed.ci, "github");
assert.deepEqual(parsed.targets, ["codex", "claude"]);
assert.equal(config.defaultProfile, "solo-product");
assert.equal(config.review.required, true);
assert.deepEqual(
config.gates.map((gate) => gate.command),
["npm run docs:check", "npm run lint", "npm test", "npm run build"],
);
assert.match(agents, /Direct Main Exceptions/);
assert.match(workflow, /npm run docs:check/);
assert.match(initSkill, /devflow init --preset/);
assert.match(initSkill, /thin wrapper/);
assert.match(initCommand, /devflow init/);
assert.equal(codexManifest.name, "devflow");
assert.equal(claudeManifest.name, "devflow");
assert.match(gitignore, /^plugins\/devflow\/$/m);
});

test("CLI health reports missing scaffold files", async () => {
const repoPath = await createTempGitRepo();

Expand Down Expand Up @@ -822,7 +886,7 @@ test("CLI harness inspect renders target readiness JSON", async () => {
await writeFile(join(repoPath, "plugins", "devflow", "hooks", "stop.mjs"), "\n", "utf8");
await writeFile(join(repoPath, "plugins", "devflow", "skills", "start", "SKILL.md"), "# Start\n", "utf8");
await writeFile(join(repoPath, "plugins", "devflow", "skills", "finish", "SKILL.md"), "# Finish\n", "utf8");
for (const skill of ["status", "doctor", "harness", "work", "gates", "review", "split", "next", "rewrite", "sessions", "explain"]) {
for (const skill of ["init", "status", "doctor", "harness", "work", "gates", "review", "split", "next", "rewrite", "sessions", "explain"]) {
await mkdir(join(repoPath, "plugins", "devflow", "skills", skill), { recursive: true });
await writeFile(join(repoPath, "plugins", "devflow", "skills", skill, "SKILL.md"), `# ${skill}\n`, "utf8");
}
Expand Down
Loading