The gap
warren init --project <id> only works when the CLI runs on the same machine as the warren server. Against a remote server it fails with project clone missing on disk, even though the docs present it as the way to scaffold config for a project warren manages.
src/cli/commands/target-dir.ts:44-53 fetches the project row over GET /projects/:id and then checks existsSync(row.localPath) on the machine running the CLI. localPath is a path on the server's filesystem, so on any other machine the check fails and throws. src/cli/commands/init.ts:114-146 then expects to mkdir and writeFile into that path locally. src/cli/commands/config-migrate.ts:80 goes through the same resolveTargetDir and has the same limitation.
There is no write route for this today. src/server/handlers/route-table.ts:192-197 serves only GET /projects/:id/warren-config, and the nearest mutation is POST /projects/:id/refresh (:230-233).
docs/onboarding-external-repos.md:18-39 documents warren init --project as step 2 of the mirror recipe, with no mention that it must run on the host. The comment at target-dir.ts:40-43 records the earlier decision that "writing into the clone only makes sense on the host", which this issue reverses.
What to build
- A server route that scaffolds
.warren/triggers.yaml and .warren/config.yaml into the project's host clone. POST /projects/:id/init with a JSON body carrying the same options the CLI accepts today (default role, prompt, provider, model, branch prefix, and an overwrite flag) is the recommended shape. The handler goes in src/server/handlers/projects.ts next to refreshProjectHandler (:443), which is the precedent for an admin-policy mutation on a project. Reuse the existing template and renderConfigYaml logic from init.ts by moving it into src/projects/ so the handler and the CLI call one implementation (the "single source of truth" rule in AGENTS.md).
- An SDK method on
WarrenClient in src/client/client.ts, beside refreshProject (:174).
- The CLI switch.
warren init --project calls the route. Keep the current local-filesystem path for the no---project case (scaffolding the current directory), which never touches the server. Apply the same change to warren config migrate --project.
- Docs. Regenerate
docs/http-api.md and docs/openapi.yaml (bun run gen:docs, bun run gen:openapi), regenerate the CLI reference if flags change (bun run gen:cli-ref), and drop the host-only assumption from docs/onboarding-external-repos.md.
Scope
Out of scope: committing the scaffolded files upstream (they stay untracked in the host clone, as today), and any change to what the templates contain.
Tests: a new src/server/handlers/projects.init.test.ts following projects.refresh.test.ts; src/cli/commands/init.test.ts gains a remote-mode case (its mockClient at :31 already models projects by localPath, so extend it with the new method); src/cli/commands/config-migrate.test.ts; src/client/client.projects-agents.test.ts. bun run lint includes check-client-contract, which fails if the UI or SDK calls a path ROUTE_TABLE does not serve, so the route and the client must land together.
Getting started
AGENTS.md covers setup, the handler and SDK conventions, and the layer rules (src/cli/** must not import src/server/**). Everything here is testable in-process with no cluster and no credentials. Run bun run check:all before pushing. Warnings count as failures.
Tracked internally as warren-166d.
The gap
warren init --project <id>only works when the CLI runs on the same machine as the warren server. Against a remote server it fails withproject clone missing on disk, even though the docs present it as the way to scaffold config for a project warren manages.src/cli/commands/target-dir.ts:44-53fetches the project row overGET /projects/:idand then checksexistsSync(row.localPath)on the machine running the CLI.localPathis a path on the server's filesystem, so on any other machine the check fails and throws.src/cli/commands/init.ts:114-146then expects tomkdirandwriteFileinto that path locally.src/cli/commands/config-migrate.ts:80goes through the sameresolveTargetDirand has the same limitation.There is no write route for this today.
src/server/handlers/route-table.ts:192-197serves onlyGET /projects/:id/warren-config, and the nearest mutation isPOST /projects/:id/refresh(:230-233).docs/onboarding-external-repos.md:18-39documentswarren init --projectas step 2 of the mirror recipe, with no mention that it must run on the host. The comment attarget-dir.ts:40-43records the earlier decision that "writing into the clone only makes sense on the host", which this issue reverses.What to build
.warren/triggers.yamland.warren/config.yamlinto the project's host clone.POST /projects/:id/initwith a JSON body carrying the same options the CLI accepts today (default role, prompt, provider, model, branch prefix, and an overwrite flag) is the recommended shape. The handler goes insrc/server/handlers/projects.tsnext torefreshProjectHandler(:443), which is the precedent for an admin-policy mutation on a project. Reuse the existing template andrenderConfigYamllogic frominit.tsby moving it intosrc/projects/so the handler and the CLI call one implementation (the "single source of truth" rule inAGENTS.md).WarrenClientinsrc/client/client.ts, besiderefreshProject(:174).warren init --projectcalls the route. Keep the current local-filesystem path for the no---projectcase (scaffolding the current directory), which never touches the server. Apply the same change towarren config migrate --project.docs/http-api.mdanddocs/openapi.yaml(bun run gen:docs,bun run gen:openapi), regenerate the CLI reference if flags change (bun run gen:cli-ref), and drop the host-only assumption fromdocs/onboarding-external-repos.md.Scope
Out of scope: committing the scaffolded files upstream (they stay untracked in the host clone, as today), and any change to what the templates contain.
Tests: a new
src/server/handlers/projects.init.test.tsfollowingprojects.refresh.test.ts;src/cli/commands/init.test.tsgains a remote-mode case (itsmockClientat:31already models projects bylocalPath, so extend it with the new method);src/cli/commands/config-migrate.test.ts;src/client/client.projects-agents.test.ts.bun run lintincludescheck-client-contract, which fails if the UI or SDK calls a pathROUTE_TABLEdoes not serve, so the route and the client must land together.Getting started
AGENTS.mdcovers setup, the handler and SDK conventions, and the layer rules (src/cli/**must not importsrc/server/**). Everything here is testable in-process with no cluster and no credentials. Runbun run check:allbefore pushing. Warnings count as failures.Tracked internally as
warren-166d.